@aiwerk/mcp-bridge 2.6.6 → 2.6.7

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.
@@ -155,6 +155,18 @@ function truncateJsonAware(value, limit) {
155
155
  return null;
156
156
  }
157
157
  function truncateArray(arr, limit) {
158
+ // For very large arrays, skip binary search (too many JSON.stringify calls)
159
+ // and use progressive halving instead
160
+ if (arr.length > 1000) {
161
+ let count = arr.length;
162
+ while (count > 1) {
163
+ count = Math.ceil(count / 2);
164
+ if (JSON.stringify(arr.slice(0, count)).length <= limit) {
165
+ return arr.slice(0, count);
166
+ }
167
+ }
168
+ return arr.slice(0, 1);
169
+ }
158
170
  // Binary search for the number of elements that fit
159
171
  let lo = 0;
160
172
  let hi = arr.length;
@@ -213,20 +225,19 @@ export function processResult(result, serverName, serverConfig, clientConfig) {
213
225
  const wasTruncated = processed !== null && typeof processed === "object" && processed._truncated === true;
214
226
  // Sanitize step (only for trust=sanitize, handled inside applyTrustLevel)
215
227
  processed = applyTrustLevel(processed, serverName, serverConfig);
216
- // If both truncated and untrusted/sanitize, flatten the metadata to top level
217
- // to avoid double-wrapping ({ _trust, result: { _truncated, result: actual } })
228
+ // If both truncated and untrusted, flatten the metadata to top level
229
+ // to avoid double-wrapping ({ _trust, result: { _truncated, result: actual } }).
230
+ // Note: sanitize mode does NOT wrap — it sanitizes in-place, so the truncation
231
+ // markers (_truncated, _originalLength) are already at the right level.
218
232
  const trust = serverConfig.trust ?? "trusted";
219
- if (wasTruncated && (trust === "untrusted" || trust === "sanitize")) {
220
- const flat = {
233
+ if (wasTruncated && trust === "untrusted") {
234
+ return {
235
+ _trust: "untrusted",
236
+ _server: serverName,
221
237
  _truncated: true,
222
238
  _originalLength: processed.result?._originalLength,
223
239
  result: processed.result?.result,
224
240
  };
225
- if (trust === "untrusted") {
226
- flat._trust = "untrusted";
227
- flat._server = serverName;
228
- }
229
- return flat;
230
241
  }
231
242
  return processed;
232
243
  }
@@ -30,6 +30,14 @@ export class StandaloneServer {
30
30
  if (this.isRouterMode()) {
31
31
  this.router = new McpRouter(config.servers ?? {}, config, logger);
32
32
  }
33
+ else {
34
+ // Warn if security config is used in direct mode where processResult() doesn't run
35
+ const hasSecurityConfig = Object.values(config.servers ?? {}).some(s => s.trust && s.trust !== "trusted" || s.maxResultChars || s.toolFilter);
36
+ if (hasSecurityConfig || config.maxResultChars) {
37
+ logger.warn("[mcp-bridge] Security config (trust/maxResultChars/toolFilter) detected in direct mode. " +
38
+ "These settings only apply in router mode. Consider switching to mode: \"router\".");
39
+ }
40
+ }
33
41
  }
34
42
  isRouterMode() {
35
43
  return (this.config.mode ?? "router") === "router";
@@ -106,6 +106,8 @@ export class BaseTransport {
106
106
  this.scheduleReconnect();
107
107
  }
108
108
  }, reconnectInterval);
109
+ // Allow Node.js process to exit gracefully even if reconnect is pending
110
+ this.reconnectTimer.unref();
109
111
  }
110
112
  /** Cancel any scheduled reconnection timer. */
111
113
  cleanupReconnectTimer() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aiwerk/mcp-bridge",
3
- "version": "2.6.6",
3
+ "version": "2.6.7",
4
4
  "description": "Standalone MCP server that multiplexes multiple MCP servers into one interface",
5
5
  "type": "module",
6
6
  "main": "./dist/src/index.js",