@alfe.ai/mcp-bundler 0.0.1 → 0.1.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.
package/dist/index.cjs CHANGED
@@ -1,4 +1,7 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ let node_fs = require("node:fs");
3
+ let node_path = require("node:path");
4
+ let node_os = require("node:os");
2
5
  //#region src/tool-naming.ts
3
6
  /**
4
7
  * Tool name sanitization and collision handling.
@@ -450,11 +453,455 @@ var McpBundler = class {
450
453
  }
451
454
  };
452
455
  //#endregion
456
+ //#region src/store.ts
457
+ const DEFAULT_STORE_PATH = (0, node_path.join)((0, node_path.join)((0, node_os.homedir)(), ".alfe", "mcp"), "servers.json");
458
+ /** Inter-process lock tunings — exported as constants so tests can override. */
459
+ const LOCK_WAIT_MS = 5e3;
460
+ const LOCK_RETRY_INTERVAL_MS = 25;
461
+ const LOCK_STALE_MS = 1e4;
462
+ /**
463
+ * On-disk source of truth for the bundler's configured servers.
464
+ *
465
+ * Mutations go through `update()` (read-modify-write with atomic
466
+ * temp+rename) so a concurrent writer (e.g. two `alfe mcp add` invocations
467
+ * racing) can't lose data — the second writer reads the first's state.
468
+ *
469
+ * Schema is owner-tagged so `removeServersByOwner` can implement
470
+ * integration uninstall without touching CLI-owned or manual entries.
471
+ */
472
+ var Store = class {
473
+ storePath;
474
+ logger;
475
+ watcher;
476
+ watcherListeners = /* @__PURE__ */ new Set();
477
+ rewatchTimer;
478
+ constructor(opts = {}) {
479
+ this.storePath = opts.path ?? DEFAULT_STORE_PATH;
480
+ this.logger = opts.logger;
481
+ }
482
+ get path() {
483
+ return this.storePath;
484
+ }
485
+ read() {
486
+ if (!(0, node_fs.existsSync)(this.storePath)) return cloneEmpty();
487
+ try {
488
+ const raw = (0, node_fs.readFileSync)(this.storePath, "utf8");
489
+ return normalize(JSON.parse(raw));
490
+ } catch (err) {
491
+ this.logger?.warn("[mcp-bundler/store] failed to read store; returning empty", {
492
+ err: errMsg$1(err),
493
+ path: this.storePath
494
+ });
495
+ return cloneEmpty();
496
+ }
497
+ }
498
+ /**
499
+ * Read-modify-write with atomic temp+rename, guarded by an
500
+ * inter-process lock file. Caller passes a pure function that
501
+ * produces the next state; this serialises the mutation to disk in
502
+ * one rename, which is atomic on POSIX and on Windows when the
503
+ * target path is on the same volume.
504
+ *
505
+ * The lock guards the read-then-rename window so two processes
506
+ * (e.g. two `alfe mcp add` shells, or the CLI racing the daemon)
507
+ * can't drop each other's writes. The lock file is at
508
+ * `<storePath>.lock`; stale locks (older than `LOCK_STALE_MS`) are
509
+ * stolen so a crashed writer doesn't wedge the store.
510
+ *
511
+ * Pure-function shape (instead of a `read()` then `write(next)`
512
+ * pair) intentionally — it keeps the read-modify-write contract
513
+ * local to each caller so two updates back-to-back never see each
514
+ * other's partial state.
515
+ */
516
+ update(fn) {
517
+ (0, node_fs.mkdirSync)((0, node_path.dirname)(this.storePath), { recursive: true });
518
+ const release = this.acquireLock();
519
+ try {
520
+ const next = fn(this.read());
521
+ const tempPath = `${this.storePath}.${String(process.pid)}.${String(Date.now())}.tmp`;
522
+ (0, node_fs.writeFileSync)(tempPath, JSON.stringify(next, null, 2), {
523
+ encoding: "utf8",
524
+ mode: 384
525
+ });
526
+ try {
527
+ (0, node_fs.renameSync)(tempPath, this.storePath);
528
+ } catch (err) {
529
+ try {
530
+ (0, node_fs.unlinkSync)(tempPath);
531
+ } catch {}
532
+ throw err;
533
+ }
534
+ return next;
535
+ } finally {
536
+ release();
537
+ }
538
+ }
539
+ /**
540
+ * Acquire an inter-process file lock by atomically creating a
541
+ * sentinel via `openSync(lockPath, 'wx')`. Spins with bounded
542
+ * backoff up to `LOCK_WAIT_MS`. If the lock file is older than
543
+ * `LOCK_STALE_MS` it's assumed orphaned (writer crashed mid-update)
544
+ * and stolen — the write window is sub-second in practice, so
545
+ * holding the lock for >5s means something went wrong.
546
+ *
547
+ * Returns the release function. Single-process callers are
548
+ * unaffected — re-entering the same process spins briefly while
549
+ * the prior call's `finally` runs.
550
+ */
551
+ acquireLock() {
552
+ const lockPath = `${this.storePath}.lock`;
553
+ const deadline = Date.now() + LOCK_WAIT_MS;
554
+ let fd = -1;
555
+ for (;;) try {
556
+ fd = (0, node_fs.openSync)(lockPath, "wx", 384);
557
+ break;
558
+ } catch (err) {
559
+ if (err.code !== "EEXIST") throw err;
560
+ if (this.lockIsStale(lockPath)) {
561
+ try {
562
+ (0, node_fs.unlinkSync)(lockPath);
563
+ } catch {}
564
+ continue;
565
+ }
566
+ if (Date.now() >= deadline) throw new Error(`Store.update: timed out waiting for ${lockPath} (held by another writer or stale lock)`);
567
+ const sleepUntil = Date.now() + LOCK_RETRY_INTERVAL_MS;
568
+ while (Date.now() < sleepUntil);
569
+ }
570
+ const held = fd;
571
+ return () => {
572
+ try {
573
+ (0, node_fs.closeSync)(held);
574
+ } catch {}
575
+ try {
576
+ (0, node_fs.unlinkSync)(lockPath);
577
+ } catch {}
578
+ };
579
+ }
580
+ lockIsStale(lockPath) {
581
+ try {
582
+ const st = (0, node_fs.statSync)(lockPath);
583
+ return Date.now() - st.mtimeMs > LOCK_STALE_MS;
584
+ } catch {
585
+ return false;
586
+ }
587
+ }
588
+ /**
589
+ * Watch the store file for external changes (e.g. another `alfe mcp add`
590
+ * shelling out from a separate process). Returns an unsubscribe fn.
591
+ *
592
+ * Coalesces bursts via a 50 ms debounce — editors and atomic-rename
593
+ * writers commonly fire multiple events per logical save.
594
+ */
595
+ watch(cb) {
596
+ this.watcherListeners.add(cb);
597
+ this.ensureWatcher();
598
+ return () => {
599
+ this.watcherListeners.delete(cb);
600
+ if (this.watcherListeners.size === 0) this.disposeWatcher();
601
+ };
602
+ }
603
+ dispose() {
604
+ this.watcherListeners.clear();
605
+ this.disposeWatcher();
606
+ }
607
+ ensureWatcher() {
608
+ if (this.watcher) return;
609
+ (0, node_fs.mkdirSync)((0, node_path.dirname)(this.storePath), { recursive: true });
610
+ const dir = (0, node_path.dirname)(this.storePath);
611
+ const basename = this.storePath.slice(dir.length + 1);
612
+ let pending;
613
+ const fire = () => {
614
+ pending = void 0;
615
+ for (const cb of this.watcherListeners) try {
616
+ cb();
617
+ } catch (err) {
618
+ this.logger?.warn("[mcp-bundler/store] watcher listener threw", { err: errMsg$1(err) });
619
+ }
620
+ };
621
+ try {
622
+ this.watcher = (0, node_fs.watch)(dir, (_event, fn) => {
623
+ if (fn !== basename) return;
624
+ if (pending) clearTimeout(pending);
625
+ pending = setTimeout(fire, 50);
626
+ });
627
+ this.watcher.on("error", (err) => {
628
+ this.logger?.warn("[mcp-bundler/store] watcher error; retrying in 1s", { err: errMsg$1(err) });
629
+ this.disposeWatcher();
630
+ if (!this.rewatchTimer && this.watcherListeners.size > 0) {
631
+ this.rewatchTimer = setTimeout(() => {
632
+ this.rewatchTimer = void 0;
633
+ this.ensureWatcher();
634
+ }, 1e3);
635
+ this.rewatchTimer.unref();
636
+ }
637
+ });
638
+ } catch (err) {
639
+ this.logger?.warn("[mcp-bundler/store] failed to start watcher", { err: errMsg$1(err) });
640
+ }
641
+ }
642
+ disposeWatcher() {
643
+ if (this.watcher) {
644
+ try {
645
+ this.watcher.close();
646
+ } catch {}
647
+ this.watcher = void 0;
648
+ }
649
+ if (this.rewatchTimer) {
650
+ clearTimeout(this.rewatchTimer);
651
+ this.rewatchTimer = void 0;
652
+ }
653
+ }
654
+ };
655
+ function defaultStorePath() {
656
+ return DEFAULT_STORE_PATH;
657
+ }
658
+ /** Pull the runtime config (transport + transport-specific fields) out of a stored entry. */
659
+ function toServerConfig(entry) {
660
+ if (entry.transport === "stdio") {
661
+ const { command, args, env, cwd } = entry;
662
+ const cfg = { command };
663
+ if (args) cfg.args = args;
664
+ if (env) cfg.env = env;
665
+ if (cwd) cfg.cwd = cwd;
666
+ return cfg;
667
+ }
668
+ const { url, transport, headers, connectionTimeoutMs } = entry;
669
+ const cfg = {
670
+ url,
671
+ transport
672
+ };
673
+ if (headers) cfg.headers = headers;
674
+ if (connectionTimeoutMs !== void 0) cfg.connectionTimeoutMs = connectionTimeoutMs;
675
+ return cfg;
676
+ }
677
+ /** Build a stored entry from a runtime config + ownership metadata. */
678
+ function toStoredEntry(config, meta) {
679
+ const addedAt = meta.addedAt ?? (/* @__PURE__ */ new Date()).toISOString();
680
+ if ("command" in config) return {
681
+ transport: "stdio",
682
+ owner: meta.owner,
683
+ addedAt,
684
+ ...meta.version !== void 0 ? { version: meta.version } : {},
685
+ ...config
686
+ };
687
+ const transport = meta.transport ?? config.transport ?? "sse";
688
+ if (transport === "stdio") throw new Error("toStoredEntry: transport=stdio specified but config is remote-shaped");
689
+ return {
690
+ transport,
691
+ owner: meta.owner,
692
+ addedAt,
693
+ ...meta.version !== void 0 ? { version: meta.version } : {},
694
+ ...config
695
+ };
696
+ }
697
+ function cloneEmpty() {
698
+ return {
699
+ servers: {},
700
+ config: {},
701
+ _ownedOpenclawKeys: []
702
+ };
703
+ }
704
+ function normalize(raw) {
705
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) return cloneEmpty();
706
+ const r = raw;
707
+ return {
708
+ servers: r.servers && typeof r.servers === "object" ? r.servers : {},
709
+ config: r.config && typeof r.config === "object" ? r.config : {},
710
+ _ownedOpenclawKeys: Array.isArray(r._ownedOpenclawKeys) ? r._ownedOpenclawKeys.slice() : []
711
+ };
712
+ }
713
+ function errMsg$1(err) {
714
+ return err instanceof Error ? err.message : String(err);
715
+ }
716
+ //#endregion
717
+ //#region src/manager.ts
718
+ /**
719
+ * Bundler manager — owns the `~/.alfe/mcp/servers.json` store and surfaces a
720
+ * small CRUD API the CLI and integration applier both call into.
721
+ *
722
+ * Single source of truth: every consumer (daemon-hosted bundler, CLI `alfe mcp
723
+ * list`, integration uninstall) reads from this store. Openclaw.json is no
724
+ * longer kept in sync — the daemon hosts the bundler children and the
725
+ * openclaw plugin reaches them via IPC, so the openclaw.json mirror became
726
+ * dead weight and an active source of duplicate spawning on claude-cli /
727
+ * codex-cli backends.
728
+ *
729
+ * Call `loadIntoBundler(bundler)` once at daemon startup to wire the store
730
+ * into a live `McpBundler` — subsequent store mutations (including those
731
+ * landed by other processes via the file watcher) re-reconcile automatically.
732
+ */
733
+ var Manager = class {
734
+ store;
735
+ logger;
736
+ bundler;
737
+ changeListeners = /* @__PURE__ */ new Set();
738
+ storeUnsubscribe;
739
+ constructor(opts = {}) {
740
+ this.store = opts.store ?? new Store({ logger: opts.logger });
741
+ this.logger = opts.logger;
742
+ }
743
+ /** Direct accessor — handy for tests and the CLI's `alfe mcp list`. */
744
+ getStore() {
745
+ return this.store;
746
+ }
747
+ /**
748
+ * Register or overwrite a server entry. Mutation lands in the store
749
+ * synchronously; if a bundler has been attached via `loadIntoBundler`,
750
+ * it gets re-reconciled in the background (errors logged, never
751
+ * thrown — the store is the source of truth, the bundler is derived).
752
+ */
753
+ async addServer(config, opts) {
754
+ if (!opts.id) throw new Error("Manager.addServer: id is required");
755
+ const owner = opts.owner ?? "manual";
756
+ this.store.update((cur) => {
757
+ const previousAddedAt = lookupAddedAt(cur.servers, opts.id);
758
+ const entry = toStoredEntry(config, {
759
+ owner,
760
+ transport: opts.transport,
761
+ version: opts.version,
762
+ addedAt: previousAddedAt
763
+ });
764
+ return {
765
+ ...cur,
766
+ servers: {
767
+ ...cur.servers,
768
+ [opts.id]: entry
769
+ }
770
+ };
771
+ });
772
+ this.scheduleBundlerReconcile();
773
+ this.fireChange();
774
+ return Promise.resolve();
775
+ }
776
+ /**
777
+ * Remove a single server entry. No-op if the id isn't in the store.
778
+ * Refuses to remove an entry whose owner doesn't match `expectedOwner`
779
+ * when supplied — the CLI uses this to guard `alfe mcp remove` from
780
+ * accidentally clobbering integration- or cli-owned entries.
781
+ */
782
+ removeServer(id, opts = {}) {
783
+ const existing = lookupEntry(this.store.read().servers, id);
784
+ if (!existing) return Promise.resolve(false);
785
+ 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}"`));
786
+ this.store.update((cur) => ({
787
+ ...cur,
788
+ servers: Object.fromEntries(Object.entries(cur.servers).filter(([k]) => k !== id))
789
+ }));
790
+ this.scheduleBundlerReconcile();
791
+ this.fireChange();
792
+ return Promise.resolve(true);
793
+ }
794
+ /** Drop every entry whose owner matches — used by integration uninstall. */
795
+ async removeServersByOwner(owner) {
796
+ const removed = [];
797
+ this.store.update((cur) => {
798
+ const next = {};
799
+ for (const [id, entry] of Object.entries(cur.servers)) if (entry.owner === owner) removed.push(id);
800
+ else next[id] = entry;
801
+ if (removed.length === 0) return cur;
802
+ return {
803
+ ...cur,
804
+ servers: next
805
+ };
806
+ });
807
+ if (removed.length > 0) {
808
+ this.scheduleBundlerReconcile();
809
+ this.fireChange();
810
+ }
811
+ return Promise.resolve(removed);
812
+ }
813
+ /** Read-only snapshot for `alfe mcp list` and similar UIs. */
814
+ listServers() {
815
+ const snap = this.store.read();
816
+ return Object.entries(snap.servers).map(([id, entry]) => ({
817
+ id,
818
+ entry
819
+ }));
820
+ }
821
+ /**
822
+ * Push the current store contents into a bundler instance (which owns
823
+ * connections / tools). Wires up a store watcher so external mutations
824
+ * (e.g. another shell running `alfe mcp add`) re-reconcile.
825
+ */
826
+ async loadIntoBundler(bundler) {
827
+ this.bundler = bundler;
828
+ await this.reconcileBundler();
829
+ this.storeUnsubscribe ??= this.store.watch(() => {
830
+ this.reconcileBundler().catch((err) => {
831
+ this.logger?.warn("[mcp-bundler/manager] watcher reconcile failed", { err: errMsg(err) });
832
+ });
833
+ });
834
+ }
835
+ /** Subscribe to store mutations. Returns an unsubscribe fn. */
836
+ onChange(cb) {
837
+ this.changeListeners.add(cb);
838
+ return () => {
839
+ this.changeListeners.delete(cb);
840
+ };
841
+ }
842
+ /**
843
+ * Detach from the bundler and stop watching the store. Safe to call
844
+ * multiple times. Does not dispose the underlying `Store` so the
845
+ * shared instance survives multi-manager environments (rare).
846
+ */
847
+ async dispose() {
848
+ if (this.storeUnsubscribe) {
849
+ this.storeUnsubscribe();
850
+ this.storeUnsubscribe = void 0;
851
+ }
852
+ this.store.dispose();
853
+ this.changeListeners.clear();
854
+ this.bundler = void 0;
855
+ return Promise.resolve();
856
+ }
857
+ scheduleBundlerReconcile() {
858
+ if (!this.bundler) return;
859
+ this.reconcileBundler().catch((err) => {
860
+ this.logger?.warn("[mcp-bundler/manager] bundler reconcile failed", { err: errMsg(err) });
861
+ });
862
+ }
863
+ async reconcileBundler() {
864
+ if (!this.bundler) return;
865
+ const snap = this.store.read();
866
+ const servers = {};
867
+ for (const [id, entry] of Object.entries(snap.servers)) servers[id] = toServerConfig(entry);
868
+ await this.bundler.reconcile(servers);
869
+ }
870
+ fireChange() {
871
+ for (const cb of this.changeListeners) try {
872
+ cb();
873
+ } catch (err) {
874
+ this.logger?.warn("[mcp-bundler/manager] onChange listener threw", { err: errMsg(err) });
875
+ }
876
+ }
877
+ };
878
+ function errMsg(err) {
879
+ return err instanceof Error ? err.message : String(err);
880
+ }
881
+ /**
882
+ * Indexed access on `Record<string, T>` returns `T` (not `T | undefined`)
883
+ * unless `noUncheckedIndexedAccess` is set in tsconfig. These helpers
884
+ * make the optional-ness explicit so the lint rules that hate
885
+ * always-truthy conditionals stop firing on real lookups.
886
+ */
887
+ function lookupEntry(servers, id) {
888
+ return Object.hasOwn(servers, id) ? servers[id] : void 0;
889
+ }
890
+ function lookupAddedAt(servers, id) {
891
+ const entry = lookupEntry(servers, id);
892
+ return entry ? entry.addedAt : void 0;
893
+ }
894
+ //#endregion
453
895
  exports.Connection = Connection;
896
+ exports.Manager = Manager;
454
897
  exports.McpBundler = McpBundler;
455
898
  exports.STDIO_ENV_DENYLIST = STDIO_ENV_DENYLIST;
899
+ exports.Store = Store;
456
900
  exports.buildNamespacedToolName = buildNamespacedToolName;
457
901
  exports.defaultConnect = defaultConnect;
902
+ exports.defaultStorePath = defaultStorePath;
458
903
  exports.disambiguateAgainst = disambiguateAgainst;
459
904
  exports.sanitizeNameSegment = sanitizeNameSegment;
460
905
  exports.sanitizeStdioEnv = sanitizeStdioEnv;
906
+ exports.toServerConfig = toServerConfig;
907
+ exports.toStoredEntry = toStoredEntry;
package/dist/index.d.cts CHANGED
@@ -235,7 +235,203 @@ declare function buildNamespacedToolName(server: string, tool: string): string;
235
235
  */
236
236
  declare function disambiguateAgainst(candidate: string, taken: ReadonlySet<string>): string;
237
237
  //# sourceMappingURL=tool-naming.d.ts.map
238
+ //#endregion
239
+ //#region src/store.d.ts
240
+ /**
241
+ * Where a server entry came from. Used by `removeServersByOwner` so an
242
+ * integration uninstall can drop only its own entries without touching
243
+ * `cli`-owned (e.g. `alfe-platform`) or `manual`-owned (user-added) ones.
244
+ */
245
+ type ServerOwner = 'cli' | `integration:${string}` | 'manual';
246
+ interface StoredServerCommon {
247
+ /** Where the entry came from — controls bulk-removal semantics. */
248
+ owner: ServerOwner;
249
+ /** ISO timestamp of first registration; preserved across updates. */
250
+ addedAt: string;
251
+ /** Optional semver of the providing package (e.g. `@alfe.ai/mcp-server` for `alfe-platform`). Used for drift detection on CLI upgrade. */
252
+ version?: string;
253
+ }
254
+ type StoredServerEntry = (StoredServerCommon & {
255
+ transport: 'stdio';
256
+ } & StdioServerConfig) | (StoredServerCommon & {
257
+ transport: 'sse' | 'streamable-http';
258
+ } & RemoteServerConfig);
259
+ interface StoreSchema {
260
+ servers: Record<string, StoredServerEntry>;
261
+ config: {
262
+ sessionIdleTtlMs?: number;
263
+ };
264
+ /**
265
+ * Server names this manager has written into `openclaw.json#mcp.servers.*`.
266
+ * Used to compute the mirror-write diff without re-reading openclaw.json
267
+ * (which would be a second source of truth). Foreign keys not listed here
268
+ * are preserved across mirror writes.
269
+ */
270
+ _ownedOpenclawKeys: string[];
271
+ }
272
+ interface StoreOptions {
273
+ /** Absolute path to the store file. Defaults to `~/.alfe/mcp/servers.json`. */
274
+ path?: string;
275
+ logger?: Logger;
276
+ }
277
+ /**
278
+ * On-disk source of truth for the bundler's configured servers.
279
+ *
280
+ * Mutations go through `update()` (read-modify-write with atomic
281
+ * temp+rename) so a concurrent writer (e.g. two `alfe mcp add` invocations
282
+ * racing) can't lose data — the second writer reads the first's state.
283
+ *
284
+ * Schema is owner-tagged so `removeServersByOwner` can implement
285
+ * integration uninstall without touching CLI-owned or manual entries.
286
+ */
287
+ declare class Store {
288
+ private readonly storePath;
289
+ private readonly logger?;
290
+ private watcher?;
291
+ private watcherListeners;
292
+ private rewatchTimer?;
293
+ constructor(opts?: StoreOptions);
294
+ get path(): string;
295
+ read(): StoreSchema;
296
+ /**
297
+ * Read-modify-write with atomic temp+rename, guarded by an
298
+ * inter-process lock file. Caller passes a pure function that
299
+ * produces the next state; this serialises the mutation to disk in
300
+ * one rename, which is atomic on POSIX and on Windows when the
301
+ * target path is on the same volume.
302
+ *
303
+ * The lock guards the read-then-rename window so two processes
304
+ * (e.g. two `alfe mcp add` shells, or the CLI racing the daemon)
305
+ * can't drop each other's writes. The lock file is at
306
+ * `<storePath>.lock`; stale locks (older than `LOCK_STALE_MS`) are
307
+ * stolen so a crashed writer doesn't wedge the store.
308
+ *
309
+ * Pure-function shape (instead of a `read()` then `write(next)`
310
+ * pair) intentionally — it keeps the read-modify-write contract
311
+ * local to each caller so two updates back-to-back never see each
312
+ * other's partial state.
313
+ */
314
+ update(fn: (cur: StoreSchema) => StoreSchema): StoreSchema;
315
+ /**
316
+ * Acquire an inter-process file lock by atomically creating a
317
+ * sentinel via `openSync(lockPath, 'wx')`. Spins with bounded
318
+ * backoff up to `LOCK_WAIT_MS`. If the lock file is older than
319
+ * `LOCK_STALE_MS` it's assumed orphaned (writer crashed mid-update)
320
+ * and stolen — the write window is sub-second in practice, so
321
+ * holding the lock for >5s means something went wrong.
322
+ *
323
+ * Returns the release function. Single-process callers are
324
+ * unaffected — re-entering the same process spins briefly while
325
+ * the prior call's `finally` runs.
326
+ */
327
+ private acquireLock;
328
+ private lockIsStale;
329
+ /**
330
+ * Watch the store file for external changes (e.g. another `alfe mcp add`
331
+ * shelling out from a separate process). Returns an unsubscribe fn.
332
+ *
333
+ * Coalesces bursts via a 50 ms debounce — editors and atomic-rename
334
+ * writers commonly fire multiple events per logical save.
335
+ */
336
+ watch(cb: () => void): () => void;
337
+ dispose(): void;
338
+ private ensureWatcher;
339
+ private disposeWatcher;
340
+ }
341
+ declare function defaultStorePath(): string;
342
+ /** Pull the runtime config (transport + transport-specific fields) out of a stored entry. */
343
+ declare function toServerConfig(entry: StoredServerEntry): McpServerConfig;
344
+ /** Build a stored entry from a runtime config + ownership metadata. */
345
+ declare function toStoredEntry(config: McpServerConfig, meta: {
346
+ owner: ServerOwner;
347
+ transport?: McpTransportKind;
348
+ version?: string;
349
+ addedAt?: string;
350
+ }): StoredServerEntry;
351
+ //#endregion
352
+ //#region src/manager.d.ts
353
+ interface ManagerOptions {
354
+ /** Pre-constructed store. If omitted, one is built with default options. */
355
+ store?: Store;
356
+ logger?: Logger;
357
+ }
358
+ interface AddServerOptions {
359
+ /** Required — flat-namespace key under the bundler store. */
360
+ id: string;
361
+ /** Marks ownership for bulk removal. Defaults to `manual`. */
362
+ owner?: ServerOwner;
363
+ /** Semver of the providing package; used for CLI version-drift detection. */
364
+ version?: string;
365
+ /** Explicit transport hint for remote configs. Defaults to inferring from `config`. */
366
+ transport?: McpTransportKind;
367
+ }
368
+ /**
369
+ * Bundler manager — owns the `~/.alfe/mcp/servers.json` store and surfaces a
370
+ * small CRUD API the CLI and integration applier both call into.
371
+ *
372
+ * Single source of truth: every consumer (daemon-hosted bundler, CLI `alfe mcp
373
+ * list`, integration uninstall) reads from this store. Openclaw.json is no
374
+ * longer kept in sync — the daemon hosts the bundler children and the
375
+ * openclaw plugin reaches them via IPC, so the openclaw.json mirror became
376
+ * dead weight and an active source of duplicate spawning on claude-cli /
377
+ * codex-cli backends.
378
+ *
379
+ * Call `loadIntoBundler(bundler)` once at daemon startup to wire the store
380
+ * into a live `McpBundler` — subsequent store mutations (including those
381
+ * landed by other processes via the file watcher) re-reconcile automatically.
382
+ */
383
+ declare class Manager {
384
+ private readonly store;
385
+ private readonly logger?;
386
+ private bundler?;
387
+ private changeListeners;
388
+ private storeUnsubscribe?;
389
+ constructor(opts?: ManagerOptions);
390
+ /** Direct accessor — handy for tests and the CLI's `alfe mcp list`. */
391
+ getStore(): Store;
392
+ /**
393
+ * Register or overwrite a server entry. Mutation lands in the store
394
+ * synchronously; if a bundler has been attached via `loadIntoBundler`,
395
+ * it gets re-reconciled in the background (errors logged, never
396
+ * thrown — the store is the source of truth, the bundler is derived).
397
+ */
398
+ addServer(config: McpServerConfig, opts: AddServerOptions): Promise<void>;
399
+ /**
400
+ * Remove a single server entry. No-op if the id isn't in the store.
401
+ * Refuses to remove an entry whose owner doesn't match `expectedOwner`
402
+ * when supplied — the CLI uses this to guard `alfe mcp remove` from
403
+ * accidentally clobbering integration- or cli-owned entries.
404
+ */
405
+ removeServer(id: string, opts?: {
406
+ expectedOwner?: ServerOwner;
407
+ }): Promise<boolean>;
408
+ /** Drop every entry whose owner matches — used by integration uninstall. */
409
+ removeServersByOwner(owner: ServerOwner): Promise<string[]>;
410
+ /** Read-only snapshot for `alfe mcp list` and similar UIs. */
411
+ listServers(): {
412
+ id: string;
413
+ entry: StoredServerEntry;
414
+ }[];
415
+ /**
416
+ * Push the current store contents into a bundler instance (which owns
417
+ * connections / tools). Wires up a store watcher so external mutations
418
+ * (e.g. another shell running `alfe mcp add`) re-reconcile.
419
+ */
420
+ loadIntoBundler(bundler: McpBundler): Promise<void>;
421
+ /** Subscribe to store mutations. Returns an unsubscribe fn. */
422
+ onChange(cb: () => void): () => void;
423
+ /**
424
+ * Detach from the bundler and stop watching the store. Safe to call
425
+ * multiple times. Does not dispose the underlying `Store` so the
426
+ * shared instance survives multi-manager environments (rare).
427
+ */
428
+ dispose(): Promise<void>;
429
+ private scheduleBundlerReconcile;
430
+ private reconcileBundler;
431
+ private fireChange;
432
+ }
433
+ //# sourceMappingURL=manager.d.ts.map
238
434
 
239
435
  //#endregion
240
- export { type BundlerOptions, Connection, type ConnectionDeps, type Logger, McpBundler, type McpClientHandle, type McpServerConfig, type McpToolCallResult, type McpToolDescriptor, type McpTransportKind, type ReconcileDiff, type RemoteServerConfig, STDIO_ENV_DENYLIST, type StdioServerConfig, buildNamespacedToolName, defaultConnect, disambiguateAgainst, sanitizeNameSegment, sanitizeStdioEnv };
436
+ export { type AddServerOptions, type BundlerOptions, Connection, type ConnectionDeps, type Logger, Manager, type ManagerOptions, McpBundler, type McpClientHandle, type McpServerConfig, type McpToolCallResult, type McpToolDescriptor, type McpTransportKind, type ReconcileDiff, type RemoteServerConfig, STDIO_ENV_DENYLIST, type ServerOwner, type StdioServerConfig, Store, type StoreOptions, type StoreSchema, type StoredServerEntry, buildNamespacedToolName, defaultConnect, defaultStorePath, disambiguateAgainst, sanitizeNameSegment, sanitizeStdioEnv, toServerConfig, toStoredEntry };
241
437
  //# sourceMappingURL=index.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.cts","names":[],"sources":["../src/types.ts","../src/connection.ts","../src/bundler.ts","../src/tool-naming.ts"],"mappings":"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"}
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../src/types.ts","../src/connection.ts","../src/bundler.ts","../src/tool-naming.ts","../src/store.ts","../src/manager.ts"],"mappings":"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"}