@alfe.ai/mcp-bundler 0.1.0 → 0.2.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
@@ -350,36 +350,13 @@ declare function toStoredEntry(config: McpServerConfig, meta: {
350
350
  }): StoredServerEntry;
351
351
  //#endregion
352
352
  //#region src/manager.d.ts
353
- /**
354
- * Shells out to `openclaw config set --batch-json` / `openclaw config unset`
355
- * to keep `openclaw.json#mcp.servers.*` in sync with the bundler store.
356
- * Default executor reuses the same machinery the integrations applier has
357
- * used for ~6 months; tests inject a fake.
358
- */
359
- interface OpenclawExecutor {
360
- setBatch: (batch: {
361
- path: string;
362
- value: unknown;
363
- }[]) => Promise<void>;
364
- unset: (path: string) => Promise<void>;
365
- }
366
- declare const defaultOpenclawExecutor: OpenclawExecutor;
367
353
  interface ManagerOptions {
368
354
  /** Pre-constructed store. If omitted, one is built with default options. */
369
355
  store?: Store;
370
- /** Override for the openclaw mirror executor (tests inject a fake). */
371
- executor?: OpenclawExecutor;
372
356
  logger?: Logger;
373
- /**
374
- * Debounce window for the mirror-write. Mutations landing inside this
375
- * window coalesce into a single openclaw config update, avoiding the
376
- * auto-restart race where two back-to-back `addServer` calls hit an
377
- * openclaw that's mid-shutdown from the first write's watcher.
378
- */
379
- mirrorDebounceMs?: number;
380
357
  }
381
358
  interface AddServerOptions {
382
- /** Required — flat-namespace key under `mcp.servers.*`. */
359
+ /** Required — flat-namespace key under the bundler store. */
383
360
  id: string;
384
361
  /** Marks ownership for bulk removal. Defaults to `manual`. */
385
362
  owner?: ServerOwner;
@@ -389,21 +366,23 @@ interface AddServerOptions {
389
366
  transport?: McpTransportKind;
390
367
  }
391
368
  /**
392
- * Bundler manager — owns the alfe store, mirrors it into openclaw.json,
393
- * and surfaces a small CRUD API the CLI and integration applier both
394
- * call into.
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.
395
378
  *
396
- * The store is the Alfe-owned source of truth; openclaw.json is a
397
- * derived mirror so the runtime keeps consuming its existing format.
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.
398
382
  */
399
383
  declare class Manager {
400
384
  private readonly store;
401
- private readonly executor;
402
385
  private readonly logger?;
403
- private readonly mirrorDebounceMs;
404
- private mirrorTimer?;
405
- private mirrorPromise;
406
- private mirrorPending?;
407
386
  private bundler?;
408
387
  private changeListeners;
409
388
  private storeUnsubscribe?;
@@ -411,10 +390,10 @@ declare class Manager {
411
390
  /** Direct accessor — handy for tests and the CLI's `alfe mcp list`. */
412
391
  getStore(): Store;
413
392
  /**
414
- * Register or overwrite a server entry. Resolves as soon as the store
415
- * mutation is committed to disk the openclaw.json mirror runs async
416
- * in the background and is debounced so back-to-back calls coalesce
417
- * into one runtime restart. Call `flush()` to await the mirror.
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).
418
397
  */
419
398
  addServer(config: McpServerConfig, opts: AddServerOptions): Promise<void>;
420
399
  /**
@@ -422,9 +401,6 @@ declare class Manager {
422
401
  * Refuses to remove an entry whose owner doesn't match `expectedOwner`
423
402
  * when supplied — the CLI uses this to guard `alfe mcp remove` from
424
403
  * accidentally clobbering integration- or cli-owned entries.
425
- *
426
- * Resolves as soon as the store mutation is committed. Mirror runs
427
- * async; call `flush()` to await it.
428
404
  */
429
405
  removeServer(id: string, opts?: {
430
406
  expectedOwner?: ServerOwner;
@@ -445,30 +421,75 @@ declare class Manager {
445
421
  /** Subscribe to store mutations. Returns an unsubscribe fn. */
446
422
  onChange(cb: () => void): () => void;
447
423
  /**
448
- * Cancel any pending mirror-write, flush the in-flight one, and stop
449
- * watching the store. Safe to call multiple times.
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).
450
427
  */
451
428
  dispose(): Promise<void>;
429
+ private scheduleBundlerReconcile;
430
+ private reconcileBundler;
431
+ private fireChange;
432
+ }
433
+ //# sourceMappingURL=manager.d.ts.map
434
+ //#endregion
435
+ //#region src/pattern-a-validator.d.ts
436
+ /**
437
+ * A tool descriptor that the validator can inspect. Plugins can pass
438
+ * either {@link McpToolDescriptor} (for proxy plugins surfacing child
439
+ * tools) or a leaner local shape (for direct-MCP plugins). Both come
440
+ * down to a tool name and a JSON Schema parameter object.
441
+ */
442
+ interface ValidatableTool {
443
+ /** Tool name as the LLM sees it (post-namespacing). */
444
+ name: string;
445
+ /** JSON Schema for tool parameters (the `inputSchema`). */
446
+ parameters: Record<string, unknown>;
447
+ }
448
+ interface PatternAOptions {
452
449
  /**
453
- * Force the debounced mirror to run now and wait for it to finish.
454
- * Surfaces the executor error if the mirror failed — callers wrap in
455
- * try/catch (or .rejects in tests) if they need to handle it.
450
+ * The required selector property name. Provider-specific (Google uses
451
+ * `email`; Notion will use `workspaceId`; Xero will use `xeroTenantId`;
452
+ * MYOB will use `myobBusinessId`). Plugins MAY support more than one
453
+ * acceptable name — pass an array.
456
454
  */
457
- flush(): Promise<void>;
458
- private scheduleMirror;
459
- private runMirror;
455
+ selector: string | readonly string[];
460
456
  /**
461
- * Compute the diff between this manager's owned set and what the store
462
- * declares now, then apply the openclaw config delta. Foreign keys
463
- * (entries in openclaw.json#mcp.servers.* not in our store) are
464
- * preserved — we only touch the names we previously claimed.
457
+ * Tool names exempt from the selector requirement typically the
458
+ * `list_accounts` discovery tool and any pure-utility tools that don't
459
+ * touch credentials. Match is exact (post-namespacing).
465
460
  */
466
- private applyMirror;
467
- private reconcileBundler;
468
- private fireChange;
461
+ exempt?: readonly string[];
469
462
  }
470
- //# sourceMappingURL=manager.d.ts.map
463
+ interface PatternAViolation {
464
+ tool: string;
465
+ reason: "missing-selector-property" | "selector-not-required" | "selector-property-not-string";
466
+ detail: string;
467
+ }
468
+ /**
469
+ * Validate that every non-exempt tool's JSON Schema declares the selector
470
+ * property AND lists it in `required`. Returns the full set of violations
471
+ * so the caller can report them all in one pass — failing fast on the
472
+ * first one tends to hide cascading bugs in real plugins.
473
+ *
474
+ * The check is intentionally schema-shape-only — it does NOT execute the
475
+ * tool, call the LLM, or talk to the cloud. It's a fast structural pass
476
+ * suitable for build-time use.
477
+ */
478
+ declare function checkPatternA(tools: readonly ValidatableTool[], options: PatternAOptions): PatternAViolation[];
479
+ /**
480
+ * Thin wrapper that throws an Error listing every violation if any are
481
+ * present. Convenient for build scripts that want a single guard call.
482
+ */
483
+ declare function assertPatternA(tools: readonly ValidatableTool[], options: PatternAOptions): void;
484
+ /**
485
+ * Cast an {@link McpToolDescriptor} (proxy-plugin shape) to the leaner
486
+ * {@link ValidatableTool} the validator accepts. Useful for proxy
487
+ * plugins that already maintain a `cachedTools: McpToolDescriptor[]`
488
+ * collection.
489
+ */
490
+ declare function fromMcpDescriptor(descriptor: McpToolDescriptor): ValidatableTool;
491
+ //# sourceMappingURL=pattern-a-validator.d.ts.map
471
492
 
472
493
  //#endregion
473
- 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 OpenclawExecutor, type ReconcileDiff, type RemoteServerConfig, STDIO_ENV_DENYLIST, type ServerOwner, type StdioServerConfig, Store, type StoreOptions, type StoreSchema, type StoredServerEntry, buildNamespacedToolName, defaultConnect, defaultOpenclawExecutor, defaultStorePath, disambiguateAgainst, sanitizeNameSegment, sanitizeStdioEnv, toServerConfig, toStoredEntry };
494
+ 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 PatternAOptions, type PatternAViolation, type ReconcileDiff, type RemoteServerConfig, STDIO_ENV_DENYLIST, type ServerOwner, type StdioServerConfig, Store, type StoreOptions, type StoreSchema, type StoredServerEntry, type ValidatableTool, assertPatternA, buildNamespacedToolName, checkPatternA, defaultConnect, defaultStorePath, disambiguateAgainst, fromMcpDescriptor, sanitizeNameSegment, sanitizeStdioEnv, toServerConfig, toStoredEntry };
474
495
  //# sourceMappingURL=index.d.ts.map
@@ -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"],"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
@@ -1,8 +1,6 @@
1
1
  import { closeSync, existsSync, mkdirSync, openSync, readFileSync, renameSync, statSync, unlinkSync, watch, writeFileSync } from "node:fs";
2
2
  import { dirname, join } from "node:path";
3
3
  import { homedir } from "node:os";
4
- import { execFile } from "node:child_process";
5
- import { promisify } from "node:util";
6
4
  //#region src/tool-naming.ts
7
5
  /**
8
6
  * Tool name sanitization and collision handling.
@@ -716,60 +714,40 @@ function errMsg$1(err) {
716
714
  }
717
715
  //#endregion
718
716
  //#region src/manager.ts
719
- const execFileAsync = promisify(execFile);
720
- const defaultOpenclawExecutor = {
721
- async setBatch(batch) {
722
- if (batch.length === 0) return;
723
- await execFileAsync("openclaw", [
724
- "config",
725
- "set",
726
- "--batch-json",
727
- JSON.stringify(batch)
728
- ], { timeout: 1e4 });
729
- },
730
- async unset(path) {
731
- await execFileAsync("openclaw", [
732
- "config",
733
- "unset",
734
- path
735
- ], { timeout: 1e4 });
736
- }
737
- };
738
- const DEFAULT_MIRROR_DEBOUNCE_MS = 250;
739
717
  /**
740
- * Bundler manager — owns the alfe store, mirrors it into openclaw.json,
741
- * and surfaces a small CRUD API the CLI and integration applier both
742
- * call into.
718
+ * Bundler manager — owns the `~/.alfe/mcp/servers.json` store and surfaces a
719
+ * small CRUD API the CLI and integration applier both call into.
743
720
  *
744
- * The store is the Alfe-owned source of truth; openclaw.json is a
745
- * derived mirror so the runtime keeps consuming its existing format.
721
+ * Single source of truth: every consumer (daemon-hosted bundler, CLI `alfe mcp
722
+ * list`, integration uninstall) reads from this store. Openclaw.json is no
723
+ * longer kept in sync — the daemon hosts the bundler children and the
724
+ * openclaw plugin reaches them via IPC, so the openclaw.json mirror became
725
+ * dead weight and an active source of duplicate spawning on claude-cli /
726
+ * codex-cli backends.
727
+ *
728
+ * Call `loadIntoBundler(bundler)` once at daemon startup to wire the store
729
+ * into a live `McpBundler` — subsequent store mutations (including those
730
+ * landed by other processes via the file watcher) re-reconcile automatically.
746
731
  */
747
732
  var Manager = class {
748
733
  store;
749
- executor;
750
734
  logger;
751
- mirrorDebounceMs;
752
- mirrorTimer;
753
- mirrorPromise = Promise.resolve();
754
- mirrorPending;
755
735
  bundler;
756
736
  changeListeners = /* @__PURE__ */ new Set();
757
737
  storeUnsubscribe;
758
738
  constructor(opts = {}) {
759
739
  this.store = opts.store ?? new Store({ logger: opts.logger });
760
- this.executor = opts.executor ?? defaultOpenclawExecutor;
761
740
  this.logger = opts.logger;
762
- this.mirrorDebounceMs = opts.mirrorDebounceMs ?? DEFAULT_MIRROR_DEBOUNCE_MS;
763
741
  }
764
742
  /** Direct accessor — handy for tests and the CLI's `alfe mcp list`. */
765
743
  getStore() {
766
744
  return this.store;
767
745
  }
768
746
  /**
769
- * Register or overwrite a server entry. Resolves as soon as the store
770
- * mutation is committed to disk the openclaw.json mirror runs async
771
- * in the background and is debounced so back-to-back calls coalesce
772
- * into one runtime restart. Call `flush()` to await the mirror.
747
+ * Register or overwrite a server entry. Mutation lands in the store
748
+ * synchronously; if a bundler has been attached via `loadIntoBundler`,
749
+ * it gets re-reconciled in the background (errors logged, never
750
+ * thrown the store is the source of truth, the bundler is derived).
773
751
  */
774
752
  async addServer(config, opts) {
775
753
  if (!opts.id) throw new Error("Manager.addServer: id is required");
@@ -790,7 +768,7 @@ var Manager = class {
790
768
  }
791
769
  };
792
770
  });
793
- this.scheduleMirror();
771
+ this.scheduleBundlerReconcile();
794
772
  this.fireChange();
795
773
  return Promise.resolve();
796
774
  }
@@ -799,9 +777,6 @@ var Manager = class {
799
777
  * Refuses to remove an entry whose owner doesn't match `expectedOwner`
800
778
  * when supplied — the CLI uses this to guard `alfe mcp remove` from
801
779
  * accidentally clobbering integration- or cli-owned entries.
802
- *
803
- * Resolves as soon as the store mutation is committed. Mirror runs
804
- * async; call `flush()` to await it.
805
780
  */
806
781
  removeServer(id, opts = {}) {
807
782
  const existing = lookupEntry(this.store.read().servers, id);
@@ -811,7 +786,7 @@ var Manager = class {
811
786
  ...cur,
812
787
  servers: Object.fromEntries(Object.entries(cur.servers).filter(([k]) => k !== id))
813
788
  }));
814
- this.scheduleMirror();
789
+ this.scheduleBundlerReconcile();
815
790
  this.fireChange();
816
791
  return Promise.resolve(true);
817
792
  }
@@ -829,7 +804,7 @@ var Manager = class {
829
804
  };
830
805
  });
831
806
  if (removed.length > 0) {
832
- this.scheduleMirror();
807
+ this.scheduleBundlerReconcile();
833
808
  this.fireChange();
834
809
  }
835
810
  return Promise.resolve(removed);
@@ -864,16 +839,11 @@ var Manager = class {
864
839
  };
865
840
  }
866
841
  /**
867
- * Cancel any pending mirror-write, flush the in-flight one, and stop
868
- * watching the store. Safe to call multiple times.
842
+ * Detach from the bundler and stop watching the store. Safe to call
843
+ * multiple times. Does not dispose the underlying `Store` so the
844
+ * shared instance survives multi-manager environments (rare).
869
845
  */
870
846
  async dispose() {
871
- if (this.mirrorTimer) {
872
- clearTimeout(this.mirrorTimer);
873
- this.mirrorTimer = void 0;
874
- await this.runMirror();
875
- }
876
- await this.mirrorPromise.catch(() => void 0);
877
847
  if (this.storeUnsubscribe) {
878
848
  this.storeUnsubscribe();
879
849
  this.storeUnsubscribe = void 0;
@@ -881,80 +851,13 @@ var Manager = class {
881
851
  this.store.dispose();
882
852
  this.changeListeners.clear();
883
853
  this.bundler = void 0;
854
+ return Promise.resolve();
884
855
  }
885
- /**
886
- * Force the debounced mirror to run now and wait for it to finish.
887
- * Surfaces the executor error if the mirror failed — callers wrap in
888
- * try/catch (or .rejects in tests) if they need to handle it.
889
- */
890
- async flush() {
891
- if (this.mirrorTimer) {
892
- clearTimeout(this.mirrorTimer);
893
- this.mirrorTimer = void 0;
894
- await this.runMirror();
895
- }
896
- await this.mirrorPromise;
897
- }
898
- scheduleMirror() {
899
- if (this.mirrorPending) return;
900
- this.mirrorPromise = new Promise((resolve, reject) => {
901
- this.mirrorPending = {
902
- resolve,
903
- reject
904
- };
905
- });
906
- this.mirrorTimer = setTimeout(() => {
907
- this.mirrorTimer = void 0;
908
- this.runMirror();
909
- }, this.mirrorDebounceMs);
910
- this.mirrorTimer.unref();
911
- }
912
- async runMirror() {
913
- const pending = this.mirrorPending;
914
- this.mirrorPending = void 0;
915
- try {
916
- await this.applyMirror();
917
- pending?.resolve();
918
- } catch (err) {
919
- pending?.reject(err);
920
- this.logger?.error("[mcp-bundler/manager] mirror write failed", { err: errMsg(err) });
921
- }
922
- }
923
- /**
924
- * Compute the diff between this manager's owned set and what the store
925
- * declares now, then apply the openclaw config delta. Foreign keys
926
- * (entries in openclaw.json#mcp.servers.* not in our store) are
927
- * preserved — we only touch the names we previously claimed.
928
- */
929
- async applyMirror() {
930
- let previousOwned = [];
931
- let desiredOwned = [];
932
- let batch = [];
933
- this.store.update((cur) => {
934
- previousOwned = cur._ownedOpenclawKeys.slice();
935
- const entries = Object.entries(cur.servers);
936
- desiredOwned = entries.map(([id]) => id).sort();
937
- batch = entries.flatMap(([id, entry]) => renderEntryToBatch(id, entry));
938
- return {
939
- ...cur,
940
- _ownedOpenclawKeys: desiredOwned
941
- };
856
+ scheduleBundlerReconcile() {
857
+ if (!this.bundler) return;
858
+ this.reconcileBundler().catch((err) => {
859
+ this.logger?.warn("[mcp-bundler/manager] bundler reconcile failed", { err: errMsg(err) });
942
860
  });
943
- await this.executor.setBatch(batch);
944
- const toUnset = previousOwned.filter((k) => !desiredOwned.includes(k));
945
- for (const id of toUnset) try {
946
- await this.executor.unset(`mcp.servers.${id}`);
947
- } catch (err) {
948
- this.logger?.warn("[mcp-bundler/manager] mirror unset failed (continuing)", {
949
- err: errMsg(err),
950
- key: `mcp.servers.${id}`
951
- });
952
- }
953
- if (this.bundler) try {
954
- await this.reconcileBundler();
955
- } catch (err) {
956
- this.logger?.warn("[mcp-bundler/manager] post-mirror reconcile failed", { err: errMsg(err) });
957
- }
958
861
  }
959
862
  async reconcileBundler() {
960
863
  if (!this.bundler) return;
@@ -971,53 +874,6 @@ var Manager = class {
971
874
  }
972
875
  }
973
876
  };
974
- /**
975
- * Render one store entry as the set of dotted-path batch entries that
976
- * `openclaw config set --batch-json` expects.
977
- *
978
- * Mirrors the format the integrations applier already emits today so the
979
- * runtime sees the same shape regardless of which writer produced it.
980
- */
981
- function renderEntryToBatch(id, entry) {
982
- const prefix = `mcp.servers.${id}`;
983
- const out = [];
984
- if (entry.transport === "stdio") {
985
- out.push({
986
- path: `${prefix}.command`,
987
- value: entry.command
988
- });
989
- if (entry.args && entry.args.length > 0) out.push({
990
- path: `${prefix}.args`,
991
- value: entry.args
992
- });
993
- if (entry.env) for (const [k, v] of Object.entries(entry.env)) out.push({
994
- path: `${prefix}.env.${k}`,
995
- value: v
996
- });
997
- if (entry.cwd) out.push({
998
- path: `${prefix}.cwd`,
999
- value: entry.cwd
1000
- });
1001
- return out;
1002
- }
1003
- out.push({
1004
- path: `${prefix}.url`,
1005
- value: entry.url
1006
- });
1007
- out.push({
1008
- path: `${prefix}.transport`,
1009
- value: entry.transport
1010
- });
1011
- if (entry.headers) for (const [k, v] of Object.entries(entry.headers)) out.push({
1012
- path: `${prefix}.headers.${k}`,
1013
- value: v
1014
- });
1015
- if (entry.connectionTimeoutMs !== void 0) out.push({
1016
- path: `${prefix}.connectionTimeoutMs`,
1017
- value: entry.connectionTimeoutMs
1018
- });
1019
- return out;
1020
- }
1021
877
  function errMsg(err) {
1022
878
  return err instanceof Error ? err.message : String(err);
1023
879
  }
@@ -1035,6 +891,75 @@ function lookupAddedAt(servers, id) {
1035
891
  return entry ? entry.addedAt : void 0;
1036
892
  }
1037
893
  //#endregion
1038
- export { Connection, Manager, McpBundler, STDIO_ENV_DENYLIST, Store, buildNamespacedToolName, defaultConnect, defaultOpenclawExecutor, defaultStorePath, disambiguateAgainst, sanitizeNameSegment, sanitizeStdioEnv, toServerConfig, toStoredEntry };
894
+ //#region src/pattern-a-validator.ts
895
+ /**
896
+ * Validate that every non-exempt tool's JSON Schema declares the selector
897
+ * property AND lists it in `required`. Returns the full set of violations
898
+ * so the caller can report them all in one pass — failing fast on the
899
+ * first one tends to hide cascading bugs in real plugins.
900
+ *
901
+ * The check is intentionally schema-shape-only — it does NOT execute the
902
+ * tool, call the LLM, or talk to the cloud. It's a fast structural pass
903
+ * suitable for build-time use.
904
+ */
905
+ function checkPatternA(tools, options) {
906
+ const selectorNames = typeof options.selector === "string" ? [options.selector] : options.selector;
907
+ const exempt = new Set(options.exempt ?? []);
908
+ const violations = [];
909
+ for (const tool of tools) {
910
+ if (exempt.has(tool.name)) continue;
911
+ const schema = tool.parameters;
912
+ const properties = schema.properties ?? {};
913
+ const required = schema.required ?? [];
914
+ const matched = selectorNames.find((name) => name in properties);
915
+ if (!matched) {
916
+ violations.push({
917
+ tool: tool.name,
918
+ reason: "missing-selector-property",
919
+ detail: `expected one of [${selectorNames.join(", ")}] in inputSchema.properties`
920
+ });
921
+ continue;
922
+ }
923
+ if (!required.includes(matched)) {
924
+ violations.push({
925
+ tool: tool.name,
926
+ reason: "selector-not-required",
927
+ detail: `selector "${matched}" present in properties but missing from inputSchema.required`
928
+ });
929
+ continue;
930
+ }
931
+ const type = properties[matched].type;
932
+ if (type !== "string") violations.push({
933
+ tool: tool.name,
934
+ reason: "selector-property-not-string",
935
+ detail: `selector "${matched}" must be JSON Schema type=string (found ${JSON.stringify(type)})`
936
+ });
937
+ }
938
+ return violations;
939
+ }
940
+ /**
941
+ * Thin wrapper that throws an Error listing every violation if any are
942
+ * present. Convenient for build scripts that want a single guard call.
943
+ */
944
+ function assertPatternA(tools, options) {
945
+ const violations = checkPatternA(tools, options);
946
+ if (violations.length === 0) return;
947
+ const lines = violations.map((v) => ` - [${v.reason}] ${v.tool}: ${v.detail}`);
948
+ throw new Error(`Pattern A validation failed for ${String(violations.length)} tool(s):\n${lines.join("\n")}`);
949
+ }
950
+ /**
951
+ * Cast an {@link McpToolDescriptor} (proxy-plugin shape) to the leaner
952
+ * {@link ValidatableTool} the validator accepts. Useful for proxy
953
+ * plugins that already maintain a `cachedTools: McpToolDescriptor[]`
954
+ * collection.
955
+ */
956
+ function fromMcpDescriptor(descriptor) {
957
+ return {
958
+ name: descriptor.prefixed,
959
+ parameters: descriptor.parameters
960
+ };
961
+ }
962
+ //#endregion
963
+ export { Connection, Manager, McpBundler, STDIO_ENV_DENYLIST, Store, assertPatternA, buildNamespacedToolName, checkPatternA, defaultConnect, defaultStorePath, disambiguateAgainst, fromMcpDescriptor, sanitizeNameSegment, sanitizeStdioEnv, toServerConfig, toStoredEntry };
1039
964
 
1040
965
  //# sourceMappingURL=index.js.map