@yawlabs/mcp-connect 0.2.0 → 0.2.1

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/dist/index.js +42 -10
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -118,9 +118,10 @@ async function shutdownAnalytics() {
118
118
  clearInterval(flushTimer);
119
119
  flushTimer = null;
120
120
  }
121
- while (buffer.length > 0) {
121
+ for (let i = 0; i < 3 && buffer.length > 0; i++) {
122
122
  await flush();
123
123
  }
124
+ buffer.length = 0;
124
125
  }
125
126
 
126
127
  // src/meta-tools.ts
@@ -433,11 +434,21 @@ async function connectToUpstream(config, onDisconnect) {
433
434
  }
434
435
  transport = new StreamableHTTPClientTransport(new URL(config.url));
435
436
  }
436
- const connectPromise = client.connect(transport);
437
- const timeoutPromise = new Promise(
438
- (_, reject) => setTimeout(() => reject(new Error("Connection timeout after " + CONNECT_TIMEOUT + "ms")), CONNECT_TIMEOUT)
439
- );
440
- await Promise.race([connectPromise, timeoutPromise]);
437
+ let timer;
438
+ const timeoutPromise = new Promise((_, reject) => {
439
+ timer = setTimeout(() => reject(new Error("Connection timeout after " + CONNECT_TIMEOUT + "ms")), CONNECT_TIMEOUT);
440
+ });
441
+ try {
442
+ await Promise.race([client.connect(transport), timeoutPromise]);
443
+ clearTimeout(timer);
444
+ } catch (err) {
445
+ clearTimeout(timer);
446
+ try {
447
+ await client.close();
448
+ } catch {
449
+ }
450
+ throw err;
451
+ }
441
452
  log("info", "Connected to upstream", { name: config.name, namespace: config.namespace, type: config.type });
442
453
  const connection = {};
443
454
  client.onclose = () => {
@@ -647,6 +658,7 @@ var ConnectServer = class _ConnectServer {
647
658
  const newConn = await connectToUpstream(serverConfig, (ns) => this.handleUpstreamDisconnect(ns));
648
659
  this.connections.set(route.namespace, newConn);
649
660
  this.rebuildRoutes();
661
+ await this.notifyAllListsChanged();
650
662
  log("info", "Auto-reconnected to upstream", { namespace: route.namespace });
651
663
  } catch (err) {
652
664
  log("error", "Auto-reconnect failed", { namespace: route.namespace, error: err.message });
@@ -858,6 +870,7 @@ var ConnectServer = class _ConnectServer {
858
870
  log("info", "Server removed or disabled in config, deactivating", { namespace });
859
871
  await disconnectFromUpstream(connection);
860
872
  this.connections.delete(namespace);
873
+ this.idleCallCounts.delete(namespace);
861
874
  changed = true;
862
875
  continue;
863
876
  }
@@ -866,6 +879,7 @@ var ConnectServer = class _ConnectServer {
866
879
  log("info", "Server config changed, deactivating stale connection", { namespace });
867
880
  await disconnectFromUpstream(connection);
868
881
  this.connections.delete(namespace);
882
+ this.idleCallCounts.delete(namespace);
869
883
  changed = true;
870
884
  }
871
885
  }
@@ -890,11 +904,30 @@ var ConnectServer = class _ConnectServer {
890
904
  if (!filepath) {
891
905
  return { content: [{ type: "text", text: "filepath is required." }], isError: true };
892
906
  }
907
+ const ALLOWED_FILENAMES = ["claude_desktop_config.json", "mcp.json", "settings.json", "mcp_config.json"];
908
+ const basename = filepath.split(/[/\\]/).pop() || "";
909
+ if (!ALLOWED_FILENAMES.includes(basename)) {
910
+ return {
911
+ content: [
912
+ {
913
+ type: "text",
914
+ text: "Only MCP config files are allowed: " + ALLOWED_FILENAMES.join(", ") + ". Got: " + basename
915
+ }
916
+ ],
917
+ isError: true
918
+ };
919
+ }
893
920
  try {
894
- const resolved = filepath.startsWith("~") ? resolve(homedir(), filepath.slice(2)) : resolve(filepath);
921
+ const resolved = filepath.startsWith("~/") ? resolve(homedir(), filepath.slice(2)) : resolve(filepath);
895
922
  const raw = await readFile(resolved, "utf-8");
896
923
  const parsed = JSON.parse(raw);
897
- const mcpServers = parsed.mcpServers || parsed;
924
+ if (!parsed.mcpServers || typeof parsed.mcpServers !== "object") {
925
+ return {
926
+ content: [{ type: "text", text: "No mcpServers object found in " + resolved }],
927
+ isError: true
928
+ };
929
+ }
930
+ const mcpServers = parsed.mcpServers;
898
931
  if (typeof mcpServers !== "object" || Array.isArray(mcpServers)) {
899
932
  return { content: [{ type: "text", text: "No mcpServers object found in " + resolved }], isError: true };
900
933
  }
@@ -911,7 +944,6 @@ var ConnectServer = class _ConnectServer {
911
944
  };
912
945
  if (value.command) entry.command = value.command;
913
946
  if (value.args) entry.args = value.args;
914
- if (value.env) entry.env = value.env;
915
947
  if (value.url) entry.url = value.url;
916
948
  servers.push(entry);
917
949
  }
@@ -941,7 +973,7 @@ var ConnectServer = class _ConnectServer {
941
973
  content: [
942
974
  {
943
975
  type: "text",
944
- text: "Imported " + (body.imported || 0) + " servers" + (body.skipped ? ", " + body.skipped + " skipped (already exist)" : "") + " from " + resolved + ". Use mcp_connect_discover to see them."
976
+ text: "Imported " + (body.imported || 0) + " servers" + (body.skipped ? ", " + body.skipped + " skipped (already exist)" : "") + " from " + resolved + ". Note: environment variables (API keys, tokens) were NOT imported for security \u2014 set them at mcp.hosting. Use mcp_connect_discover to see imported servers."
945
977
  }
946
978
  ]
947
979
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yawlabs/mcp-connect",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "MCP orchestrator — one install, all your MCP servers, managed from the cloud",
5
5
  "license": "MIT",
6
6
  "author": "Yaw Labs <contact@yaw.sh> (https://yaw.sh)",