@alfe.ai/mcp-bundler 0.3.1 → 0.4.0

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/dist/index.d.ts CHANGED
@@ -9,6 +9,8 @@ interface StdioServerConfig {
9
9
  args?: string[];
10
10
  env?: Record<string, string>;
11
11
  cwd?: string;
12
+ /** Per-server connect+discovery bound (ms) — overrides `BundlerOptions.connectTimeoutMs`. */
13
+ connectionTimeoutMs?: number;
12
14
  }
13
15
  interface RemoteServerConfig {
14
16
  url: string;
@@ -92,6 +94,33 @@ interface BundlerOptions {
92
94
  idleTtlMs?: number;
93
95
  /** Sweep interval for idle reaping (ms). Default: 60_000 (1 min). */
94
96
  idleSweepIntervalMs?: number;
97
+ /**
98
+ * Sweep interval for re-attempting servers that failed to connect
99
+ * (`connected: false && lastError`), so a server whose backing
100
+ * credential/account/network appears AFTER the first warm self-heals without
101
+ * an operator restart (ms). 0 disables. Default: 60_000 (1 min). The
102
+ * fine-grained backoff still lives on each Connection — this is the coarse
103
+ * outer bound that keeps re-checking.
104
+ */
105
+ retrySweepIntervalMs?: number;
106
+ /**
107
+ * Upper bound (ms) on one connect + tool-discovery attempt. A hung child —
108
+ * or a cold `npx` download that never completes the MCP handshake — throws
109
+ * past this bound, which records `lastError` and arms reconnect backoff so
110
+ * the retry sweep can re-attempt. Without a bound such a server has no
111
+ * error, no diagnostics, and no self-heal path. Per-server
112
+ * `connectionTimeoutMs` overrides. 0 disables. Default: 120_000 (generous
113
+ * enough for a cold `npx` package download).
114
+ */
115
+ connectTimeoutMs?: number;
116
+ /**
117
+ * Also have the retry sweep attempt servers that have NEVER had a connect
118
+ * attempt (e.g. added after the host's warmup pass already ran). Off by
119
+ * default to preserve pure-lazy embedding semantics; the daemon — which
120
+ * eagerly warms everything — enables it so a missed warm self-heals within
121
+ * one sweep instead of stranding the server's tools until a restart.
122
+ */
123
+ retryNeverConnected?: boolean;
95
124
  /**
96
125
  * Host hook fired when a tool call fails — thrown or `isError` result.
97
126
  * Invoked best-effort (exceptions swallowed); must not block.
@@ -182,6 +211,9 @@ declare class Connection {
182
211
  private static readonly RECONNECT_BACKOFF_MAX_MS;
183
212
  private readonly onUnexpectedClose;
184
213
  private readonly onStderrLine;
214
+ private readonly connectTimeoutMs;
215
+ /** Whether any connect has ever been attempted — drives the eager retry sweep. */
216
+ private connectAttempted;
185
217
  constructor(params: {
186
218
  name: string;
187
219
  config: McpServerConfig;
@@ -191,6 +223,8 @@ declare class Connection {
191
223
  onUnexpectedClose?: () => void;
192
224
  /** Threaded to the connect factory — pipes stdio child stderr when set. */
193
225
  onStderrLine?: (line: string) => void;
226
+ /** Bound (ms) on one connect + discovery attempt. 0/undefined disables. */
227
+ connectTimeoutMs?: number;
194
228
  });
195
229
  /** Returns the most recent known tool list. May be empty if the server hasn't connected yet. */
196
230
  snapshotTools(): McpToolDescriptor[];
@@ -202,6 +236,13 @@ declare class Connection {
202
236
  failureCount(): number;
203
237
  /** Message from the most recent failed connect attempt, if any. */
204
238
  lastErrorMessage(): string | undefined;
239
+ /**
240
+ * Whether a connect was ever attempted (success or failure). A reconciled
241
+ * connection that was never warmed has neither a client nor a `lastError` —
242
+ * this flag lets an eager host's retry sweep find it without also
243
+ * resurrecting cleanly-closed (idle-reaped) connections.
244
+ */
245
+ hasConnectAttempted(): boolean;
205
246
  /** Idle timestamp for reaping. */
206
247
  idleSinceMs(): number;
207
248
  /**
@@ -210,6 +251,8 @@ declare class Connection {
210
251
  */
211
252
  ensureConnected(): Promise<void>;
212
253
  private connectAndDiscover;
254
+ /** Race the attempt against `connectTimeoutMs`; 0 disables the bound. */
255
+ private raceConnectTimeout;
213
256
  /**
214
257
  * Handle an unexpected transport close (crash / network drop). Clears the
215
258
  * dead client + tools so the next `ensureConnected` re-spawns. No-op if we
@@ -259,6 +302,11 @@ declare class McpBundler {
259
302
  private readonly idleTtlMs;
260
303
  private readonly idleSweepIntervalMs;
261
304
  private idleSweepTimer;
305
+ private readonly retrySweepIntervalMs;
306
+ private retrySweepTimer;
307
+ private retrySweepInFlight;
308
+ private readonly connectTimeoutMs;
309
+ private readonly retryNeverConnected;
262
310
  private readonly deps;
263
311
  private readonly onToolError;
264
312
  private readonly onServerCrash;
@@ -296,6 +344,30 @@ declare class McpBundler {
296
344
  * swallowed per-server (logged), so one bad server doesn't fail the batch.
297
345
  */
298
346
  warmup(): Promise<void>;
347
+ /**
348
+ * Re-attempt every server that is NOT connected but HAS a recorded connect
349
+ * failure (`connected: false && lastError`). This is the self-heal path: a
350
+ * server that failed its first warm — because its backing credential /
351
+ * account / network wasn't resolvable yet — gets reconnected once that
352
+ * dependency appears, WITHOUT needing an operator to restart the daemon.
353
+ *
354
+ * Convergence: this only calls `ensureConnected()`, which honours each
355
+ * Connection's own exponential reconnect backoff (`reconnectBlockedUntilMs`,
356
+ * 500ms → 30s cap). A server that keeps `exit(1)`-ing fast-fails while in
357
+ * backoff, so repeated sweeps are cheap and never become a tight crash-loop
358
+ * — the backoff widens with each failure. Servers that connect on their
359
+ * first warm are left alone, as are cleanly-closed (idle-reaped) ones.
360
+ *
361
+ * Lazily-added servers that were NEVER attempted (no client, no
362
+ * `lastError`) are also left alone by default — but with
363
+ * `retryNeverConnected` (the daemon's eager mode) the sweep picks them up,
364
+ * so a server added after the host's warmup pass self-heals within one
365
+ * sweep instead of stranding its tools until a restart.
366
+ *
367
+ * Returns the statuses of the servers it attempted (empty if none needed a
368
+ * retry). Never throws — per-server failures are reflected in the status.
369
+ */
370
+ retryFailed(): Promise<McpServerStatus[]>;
299
371
  /** Build the live status descriptor for one connection. */
300
372
  private statusOf;
301
373
  /** Live status for every known server. Synchronous snapshot, no I/O. */
@@ -331,6 +403,7 @@ declare class McpBundler {
331
403
  */
332
404
  dispose(): Promise<void>;
333
405
  private startIdleSweep;
406
+ private startRetrySweep;
334
407
  private sweepIdle;
335
408
  }
336
409
  //# sourceMappingURL=bundler.d.ts.map
@@ -512,8 +585,11 @@ declare class Manager {
512
585
  /**
513
586
  * Register or overwrite a server entry. Mutation lands in the store
514
587
  * synchronously; if a bundler has been attached via `loadIntoBundler`,
515
- * it gets re-reconciled in the background (errors logged, never
516
- * thrown — the store is the source of truth, the bundler is derived).
588
+ * it is re-reconciled BEFORE `onChange` listeners fire (errors logged,
589
+ * never thrown — the store is the source of truth, the bundler is
590
+ * derived). The ordering is load-bearing: the daemon's `onChange`
591
+ * handler warms the bundler's current connections, so the just-added
592
+ * server must already have its Connection object or it is never warmed.
517
593
  */
518
594
  addServer(config: McpServerConfig, opts: AddServerOptions): Promise<void>;
519
595
  /**
@@ -564,7 +640,13 @@ declare class Manager {
564
640
  * shared instance survives multi-manager environments (rare).
565
641
  */
566
642
  dispose(): Promise<void>;
567
- private scheduleBundlerReconcile;
643
+ /**
644
+ * Awaited by every mutator so `onChange` listeners observe a bundler
645
+ * that already contains the mutation. Reconcile failures are logged,
646
+ * never thrown — a mutation must not fail because the derived bundler
647
+ * hiccuped.
648
+ */
649
+ private reconcileBundlerLogged;
568
650
  private reconcileBundler;
569
651
  private fireChange;
570
652
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../src/types.ts","../src/connection.ts","../src/bundler.ts","../src/tool-naming.ts","../src/store.ts","../src/manager.ts","../src/pattern-a-validator.ts"],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/types.ts","../src/connection.ts","../src/bundler.ts","../src/tool-naming.ts","../src/store.ts","../src/manager.ts","../src/pattern-a-validator.ts"],"mappings":"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"}
package/dist/index.js CHANGED
@@ -89,6 +89,9 @@ var Connection = class Connection {
89
89
  static RECONNECT_BACKOFF_MAX_MS = 3e4;
90
90
  onUnexpectedClose;
91
91
  onStderrLine;
92
+ connectTimeoutMs;
93
+ /** Whether any connect has ever been attempted — drives the eager retry sweep. */
94
+ connectAttempted = false;
92
95
  constructor(params) {
93
96
  this.name = params.name;
94
97
  this.config = params.config;
@@ -96,6 +99,7 @@ var Connection = class Connection {
96
99
  this.logger = params.logger;
97
100
  this.onUnexpectedClose = params.onUnexpectedClose;
98
101
  this.onStderrLine = params.onStderrLine;
102
+ this.connectTimeoutMs = params.connectTimeoutMs ?? 0;
99
103
  }
100
104
  /** Returns the most recent known tool list. May be empty if the server hasn't connected yet. */
101
105
  snapshotTools() {
@@ -117,6 +121,15 @@ var Connection = class Connection {
117
121
  lastErrorMessage() {
118
122
  return this.lastError;
119
123
  }
124
+ /**
125
+ * Whether a connect was ever attempted (success or failure). A reconciled
126
+ * connection that was never warmed has neither a client nor a `lastError` —
127
+ * this flag lets an eager host's retry sweep find it without also
128
+ * resurrecting cleanly-closed (idle-reaped) connections.
129
+ */
130
+ hasConnectAttempted() {
131
+ return this.connectAttempted;
132
+ }
120
133
  /** Idle timestamp for reaping. */
121
134
  idleSinceMs() {
122
135
  return Date.now() - this.lastUsedAt;
@@ -135,23 +148,33 @@ var Connection = class Connection {
135
148
  return this.connectInFlight;
136
149
  }
137
150
  async connectAndDiscover() {
151
+ this.connectAttempted = true;
138
152
  const safeConfig = "command" in this.config ? {
139
153
  ...this.config,
140
154
  env: sanitizeStdioEnv(this.config.env)
141
155
  } : this.config;
142
156
  this.logger?.debug(`[mcp-bundler] connecting server "${this.name}"`);
143
- let client;
144
- try {
145
- client = await this.deps.connect(safeConfig, {
157
+ const attempt = (async () => {
158
+ const c = await this.deps.connect(safeConfig, {
146
159
  serverName: this.name,
147
160
  onStderrLine: this.onStderrLine
148
161
  });
149
- const advertised = await client.listTools();
150
- const connected = client;
151
- this.client = connected;
162
+ try {
163
+ return {
164
+ client: c,
165
+ advertised: await c.listTools()
166
+ };
167
+ } catch (err) {
168
+ await c.close().catch(() => void 0);
169
+ throw err;
170
+ }
171
+ })();
172
+ try {
173
+ const { client, advertised } = await this.raceConnectTimeout(attempt);
174
+ this.client = client;
152
175
  this.closing = false;
153
- connected.onClose?.(() => {
154
- this.handleUnexpectedClose(connected);
176
+ client.onClose?.(() => {
177
+ this.handleUnexpectedClose(client);
155
178
  });
156
179
  this.tools = advertised.map((t) => ({
157
180
  prefixed: buildNamespacedToolName(this.name, t.name),
@@ -167,7 +190,7 @@ var Connection = class Connection {
167
190
  this.reconnectBlockedUntilMs = 0;
168
191
  this.logger?.info(`[mcp-bundler] server "${this.name}" connected, ${this.tools.length.toString()} tool(s)`);
169
192
  } catch (err) {
170
- if (client) await client.close().catch(() => void 0);
193
+ attempt.then(({ client }) => client.close()).catch(() => void 0);
171
194
  this.consecutiveFailures += 1;
172
195
  this.lastError = err instanceof Error ? err.message : String(err);
173
196
  const backoff = Math.min(Connection.RECONNECT_BACKOFF_BASE_MS * 2 ** (this.consecutiveFailures - 1), Connection.RECONNECT_BACKOFF_MAX_MS);
@@ -175,6 +198,23 @@ var Connection = class Connection {
175
198
  throw err;
176
199
  }
177
200
  }
201
+ /** Race the attempt against `connectTimeoutMs`; 0 disables the bound. */
202
+ async raceConnectTimeout(attempt) {
203
+ const ms = this.connectTimeoutMs;
204
+ if (ms <= 0) return attempt;
205
+ let timer;
206
+ const timeout = new Promise((_, reject) => {
207
+ timer = setTimeout(() => {
208
+ reject(/* @__PURE__ */ new Error(`server "${this.name}" connect timed out after ${ms.toString()}ms — spawned but did not complete the MCP handshake/discovery`));
209
+ }, ms);
210
+ if (typeof timer === "object" && "unref" in timer) timer.unref();
211
+ });
212
+ try {
213
+ return await Promise.race([attempt, timeout]);
214
+ } finally {
215
+ clearTimeout(timer);
216
+ }
217
+ }
178
218
  /**
179
219
  * Handle an unexpected transport close (crash / network drop). Clears the
180
220
  * dead client + tools so the next `ensureConnected` re-spawns. No-op if we
@@ -334,6 +374,8 @@ async function defaultConnect(server, ctx) {
334
374
  //#region src/bundler.ts
335
375
  const DEFAULT_IDLE_TTL_MS = 600 * 1e3;
336
376
  const DEFAULT_IDLE_SWEEP_INTERVAL_MS = 60 * 1e3;
377
+ const DEFAULT_RETRY_SWEEP_INTERVAL_MS = 60 * 1e3;
378
+ const DEFAULT_CONNECT_TIMEOUT_MS = 120 * 1e3;
337
379
  /** First text content of an error result, for host error reporting. */
338
380
  function extractErrorText(result) {
339
381
  for (const item of result.content) if (item.type === "text" && typeof item.text === "string") return item.text.slice(0, 500);
@@ -354,6 +396,11 @@ var McpBundler = class {
354
396
  idleTtlMs;
355
397
  idleSweepIntervalMs;
356
398
  idleSweepTimer;
399
+ retrySweepIntervalMs;
400
+ retrySweepTimer;
401
+ retrySweepInFlight = false;
402
+ connectTimeoutMs;
403
+ retryNeverConnected;
357
404
  deps;
358
405
  onToolError;
359
406
  onServerCrash;
@@ -364,11 +411,15 @@ var McpBundler = class {
364
411
  this.logger = opts.logger;
365
412
  this.idleTtlMs = opts.idleTtlMs ?? DEFAULT_IDLE_TTL_MS;
366
413
  this.idleSweepIntervalMs = opts.idleSweepIntervalMs ?? DEFAULT_IDLE_SWEEP_INTERVAL_MS;
414
+ this.retrySweepIntervalMs = opts.retrySweepIntervalMs ?? DEFAULT_RETRY_SWEEP_INTERVAL_MS;
415
+ this.connectTimeoutMs = opts.connectTimeoutMs ?? DEFAULT_CONNECT_TIMEOUT_MS;
416
+ this.retryNeverConnected = opts.retryNeverConnected ?? false;
367
417
  this.deps = deps ?? { connect: defaultConnect };
368
418
  this.onToolError = opts.onToolError;
369
419
  this.onServerCrash = opts.onServerCrash;
370
420
  this.onServerStderr = opts.onServerStderr;
371
421
  if (this.idleTtlMs > 0) this.startIdleSweep();
422
+ if (this.retrySweepIntervalMs > 0) this.startRetrySweep();
372
423
  }
373
424
  /** Construct a Connection with the host hooks bound to its server name. */
374
425
  buildConnection(name, config) {
@@ -379,6 +430,7 @@ var McpBundler = class {
379
430
  config,
380
431
  deps: this.deps,
381
432
  logger: this.logger,
433
+ connectTimeoutMs: config.connectionTimeoutMs ?? this.connectTimeoutMs,
382
434
  ...crash ? { onUnexpectedClose: () => {
383
435
  crash(name);
384
436
  } } : {},
@@ -485,6 +537,40 @@ var McpBundler = class {
485
537
  }
486
538
  }));
487
539
  }
540
+ /**
541
+ * Re-attempt every server that is NOT connected but HAS a recorded connect
542
+ * failure (`connected: false && lastError`). This is the self-heal path: a
543
+ * server that failed its first warm — because its backing credential /
544
+ * account / network wasn't resolvable yet — gets reconnected once that
545
+ * dependency appears, WITHOUT needing an operator to restart the daemon.
546
+ *
547
+ * Convergence: this only calls `ensureConnected()`, which honours each
548
+ * Connection's own exponential reconnect backoff (`reconnectBlockedUntilMs`,
549
+ * 500ms → 30s cap). A server that keeps `exit(1)`-ing fast-fails while in
550
+ * backoff, so repeated sweeps are cheap and never become a tight crash-loop
551
+ * — the backoff widens with each failure. Servers that connect on their
552
+ * first warm are left alone, as are cleanly-closed (idle-reaped) ones.
553
+ *
554
+ * Lazily-added servers that were NEVER attempted (no client, no
555
+ * `lastError`) are also left alone by default — but with
556
+ * `retryNeverConnected` (the daemon's eager mode) the sweep picks them up,
557
+ * so a server added after the host's warmup pass self-heals within one
558
+ * sweep instead of stranding its tools until a restart.
559
+ *
560
+ * Returns the statuses of the servers it attempted (empty if none needed a
561
+ * retry). Never throws — per-server failures are reflected in the status.
562
+ */
563
+ async retryFailed() {
564
+ if (this.disposed) return [];
565
+ const targets = Array.from(this.connections.values()).filter((conn) => !conn.isConnected() && (conn.lastErrorMessage() !== void 0 || this.retryNeverConnected && !conn.hasConnectAttempted()));
566
+ if (targets.length === 0) return [];
567
+ return (await Promise.allSettled(targets.map(async (conn) => {
568
+ try {
569
+ await conn.ensureConnected();
570
+ } catch {}
571
+ return this.statusOf(conn);
572
+ }))).flatMap((r) => r.status === "fulfilled" ? [r.value] : []);
573
+ }
488
574
  /** Build the live status descriptor for one connection. */
489
575
  statusOf(conn) {
490
576
  const status = {
@@ -614,6 +700,10 @@ var McpBundler = class {
614
700
  clearInterval(this.idleSweepTimer);
615
701
  this.idleSweepTimer = void 0;
616
702
  }
703
+ if (this.retrySweepTimer) {
704
+ clearInterval(this.retrySweepTimer);
705
+ this.retrySweepTimer = void 0;
706
+ }
617
707
  await Promise.allSettled(Array.from(this.connections.values()).map((c) => c.close()));
618
708
  this.connections.clear();
619
709
  }
@@ -625,6 +715,28 @@ var McpBundler = class {
625
715
  }, this.idleSweepIntervalMs);
626
716
  if (typeof this.idleSweepTimer === "object" && "unref" in this.idleSweepTimer) this.idleSweepTimer.unref();
627
717
  }
718
+ startRetrySweep() {
719
+ this.retrySweepTimer = setInterval(() => {
720
+ if (this.retrySweepInFlight) return;
721
+ this.retrySweepInFlight = true;
722
+ this.retryFailed().then((attempted) => {
723
+ if (attempted.length === 0) return;
724
+ const healed = attempted.filter((s) => s.connected);
725
+ const stillDown = attempted.filter((s) => !s.connected);
726
+ this.logger?.debug("[mcp-bundler] retry sweep", {
727
+ attempted: attempted.length,
728
+ healed: healed.length,
729
+ stillDown: stillDown.length
730
+ });
731
+ for (const s of healed) this.logger?.info(`[mcp-bundler] server "${s.name}" self-healed on retry sweep`, { toolCount: s.toolCount });
732
+ }).catch((err) => {
733
+ this.logger?.warn("[mcp-bundler] retry sweep error", { err: err instanceof Error ? err.message : String(err) });
734
+ }).finally(() => {
735
+ this.retrySweepInFlight = false;
736
+ });
737
+ }, this.retrySweepIntervalMs);
738
+ if (typeof this.retrySweepTimer === "object" && "unref" in this.retrySweepTimer) this.retrySweepTimer.unref();
739
+ }
628
740
  async sweepIdle() {
629
741
  if (this.idleTtlMs <= 0) return;
630
742
  const targets = [];
@@ -929,8 +1041,11 @@ var Manager = class {
929
1041
  /**
930
1042
  * Register or overwrite a server entry. Mutation lands in the store
931
1043
  * synchronously; if a bundler has been attached via `loadIntoBundler`,
932
- * it gets re-reconciled in the background (errors logged, never
933
- * thrown — the store is the source of truth, the bundler is derived).
1044
+ * it is re-reconciled BEFORE `onChange` listeners fire (errors logged,
1045
+ * never thrown — the store is the source of truth, the bundler is
1046
+ * derived). The ordering is load-bearing: the daemon's `onChange`
1047
+ * handler warms the bundler's current connections, so the just-added
1048
+ * server must already have its Connection object or it is never warmed.
934
1049
  */
935
1050
  async addServer(config, opts) {
936
1051
  if (!opts.id) throw new Error("Manager.addServer: id is required");
@@ -951,9 +1066,8 @@ var Manager = class {
951
1066
  }
952
1067
  };
953
1068
  });
954
- this.scheduleBundlerReconcile();
1069
+ await this.reconcileBundlerLogged();
955
1070
  this.fireChange();
956
- return Promise.resolve();
957
1071
  }
958
1072
  /**
959
1073
  * Remove a single server entry. No-op if the id isn't in the store.
@@ -961,17 +1075,17 @@ var Manager = class {
961
1075
  * when supplied — the CLI uses this to guard `alfe mcp remove` from
962
1076
  * accidentally clobbering integration- or cli-owned entries.
963
1077
  */
964
- removeServer(id, opts = {}) {
1078
+ async removeServer(id, opts = {}) {
965
1079
  const existing = lookupEntry(this.store.read().servers, id);
966
- if (!existing) return Promise.resolve(false);
967
- if (opts.expectedOwner && existing.owner !== opts.expectedOwner) return Promise.reject(/* @__PURE__ */ new Error(`Manager.removeServer: server "${id}" is owned by "${existing.owner}", not "${opts.expectedOwner}"`));
1080
+ if (!existing) return false;
1081
+ if (opts.expectedOwner && existing.owner !== opts.expectedOwner) throw new Error(`Manager.removeServer: server "${id}" is owned by "${existing.owner}", not "${opts.expectedOwner}"`);
968
1082
  this.store.update((cur) => ({
969
1083
  ...cur,
970
1084
  servers: Object.fromEntries(Object.entries(cur.servers).filter(([k]) => k !== id))
971
1085
  }));
972
- this.scheduleBundlerReconcile();
1086
+ await this.reconcileBundlerLogged();
973
1087
  this.fireChange();
974
- return Promise.resolve(true);
1088
+ return true;
975
1089
  }
976
1090
  /** Drop every entry whose owner matches — used by integration uninstall. */
977
1091
  async removeServersByOwner(owner) {
@@ -987,10 +1101,10 @@ var Manager = class {
987
1101
  };
988
1102
  });
989
1103
  if (removed.length > 0) {
990
- this.scheduleBundlerReconcile();
1104
+ await this.reconcileBundlerLogged();
991
1105
  this.fireChange();
992
1106
  }
993
- return Promise.resolve(removed);
1107
+ return removed;
994
1108
  }
995
1109
  /** Read-only snapshot for `alfe mcp list` and similar UIs. */
996
1110
  listServers() {
@@ -1060,11 +1174,19 @@ var Manager = class {
1060
1174
  this.bundler = void 0;
1061
1175
  return Promise.resolve();
1062
1176
  }
1063
- scheduleBundlerReconcile() {
1177
+ /**
1178
+ * Awaited by every mutator so `onChange` listeners observe a bundler
1179
+ * that already contains the mutation. Reconcile failures are logged,
1180
+ * never thrown — a mutation must not fail because the derived bundler
1181
+ * hiccuped.
1182
+ */
1183
+ async reconcileBundlerLogged() {
1064
1184
  if (!this.bundler) return;
1065
- this.reconcileBundler().catch((err) => {
1185
+ try {
1186
+ await this.reconcileBundler();
1187
+ } catch (err) {
1066
1188
  this.logger?.warn("[mcp-bundler/manager] bundler reconcile failed", { err: errMsg(err) });
1067
- });
1189
+ }
1068
1190
  }
1069
1191
  async reconcileBundler() {
1070
1192
  if (!this.bundler) return;