@darkiceinteractive/mcp-conductor 2.0.0-alpha.1 → 3.0.0-beta.2

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 (276) hide show
  1. package/README.md +35 -5
  2. package/dist/bin/cli.d.ts +20 -0
  3. package/dist/bin/cli.d.ts.map +1 -0
  4. package/dist/bin/cli.js +260 -0
  5. package/dist/bin/cli.js.map +1 -0
  6. package/dist/bridge/http-server.d.ts +35 -0
  7. package/dist/bridge/http-server.d.ts.map +1 -1
  8. package/dist/bridge/http-server.js +51 -2
  9. package/dist/bridge/http-server.js.map +1 -1
  10. package/dist/bridge/index.d.ts +1 -0
  11. package/dist/bridge/index.d.ts.map +1 -1
  12. package/dist/bridge/index.js +1 -0
  13. package/dist/bridge/index.js.map +1 -1
  14. package/dist/bridge/pool.d.ts +95 -0
  15. package/dist/bridge/pool.d.ts.map +1 -0
  16. package/dist/bridge/pool.js +384 -0
  17. package/dist/bridge/pool.js.map +1 -0
  18. package/dist/cache/cache.d.ts +64 -0
  19. package/dist/cache/cache.d.ts.map +1 -0
  20. package/dist/cache/cache.js +209 -0
  21. package/dist/cache/cache.js.map +1 -0
  22. package/dist/cache/delta.d.ts +32 -0
  23. package/dist/cache/delta.d.ts.map +1 -0
  24. package/dist/cache/delta.js +131 -0
  25. package/dist/cache/delta.js.map +1 -0
  26. package/dist/cache/disk.d.ts +65 -0
  27. package/dist/cache/disk.d.ts.map +1 -0
  28. package/dist/cache/disk.js +238 -0
  29. package/dist/cache/disk.js.map +1 -0
  30. package/dist/cache/index.d.ts +53 -0
  31. package/dist/cache/index.d.ts.map +1 -0
  32. package/dist/cache/index.js +12 -0
  33. package/dist/cache/index.js.map +1 -0
  34. package/dist/cache/key.d.ts +44 -0
  35. package/dist/cache/key.d.ts.map +1 -0
  36. package/dist/cache/key.js +83 -0
  37. package/dist/cache/key.js.map +1 -0
  38. package/dist/cache/lru.d.ts +57 -0
  39. package/dist/cache/lru.d.ts.map +1 -0
  40. package/dist/cache/lru.js +112 -0
  41. package/dist/cache/lru.js.map +1 -0
  42. package/dist/cache/policy.d.ts +34 -0
  43. package/dist/cache/policy.d.ts.map +1 -0
  44. package/dist/cache/policy.js +95 -0
  45. package/dist/cache/policy.js.map +1 -0
  46. package/dist/cli/commands/doctor.d.ts +33 -0
  47. package/dist/cli/commands/doctor.d.ts.map +1 -0
  48. package/dist/cli/commands/doctor.js +135 -0
  49. package/dist/cli/commands/doctor.js.map +1 -0
  50. package/dist/cli/commands/export-servers.d.ts +22 -0
  51. package/dist/cli/commands/export-servers.d.ts.map +1 -0
  52. package/dist/cli/commands/export-servers.js +45 -0
  53. package/dist/cli/commands/export-servers.js.map +1 -0
  54. package/dist/cli/commands/import-servers.d.ts +57 -0
  55. package/dist/cli/commands/import-servers.d.ts.map +1 -0
  56. package/dist/cli/commands/import-servers.js +137 -0
  57. package/dist/cli/commands/import-servers.js.map +1 -0
  58. package/dist/cli/commands/routing.d.ts +34 -0
  59. package/dist/cli/commands/routing.d.ts.map +1 -0
  60. package/dist/cli/commands/routing.js +60 -0
  61. package/dist/cli/commands/routing.js.map +1 -0
  62. package/dist/cli/commands/test-server.d.ts +34 -0
  63. package/dist/cli/commands/test-server.d.ts.map +1 -0
  64. package/dist/cli/commands/test-server.js +86 -0
  65. package/dist/cli/commands/test-server.js.map +1 -0
  66. package/dist/cli/daemon.d.ts +60 -0
  67. package/dist/cli/daemon.d.ts.map +1 -0
  68. package/dist/cli/daemon.js +244 -0
  69. package/dist/cli/daemon.js.map +1 -0
  70. package/dist/cli/replay.d.ts +16 -0
  71. package/dist/cli/replay.d.ts.map +1 -0
  72. package/dist/cli/replay.js +89 -0
  73. package/dist/cli/replay.js.map +1 -0
  74. package/dist/cli/wizard/setup.d.ts +12 -0
  75. package/dist/cli/wizard/setup.d.ts.map +1 -0
  76. package/dist/cli/wizard/setup.js +71 -0
  77. package/dist/cli/wizard/setup.js.map +1 -0
  78. package/dist/config/defaults.d.ts.map +1 -1
  79. package/dist/config/defaults.js +4 -1
  80. package/dist/config/defaults.js.map +1 -1
  81. package/dist/config/schema.d.ts +34 -0
  82. package/dist/config/schema.d.ts.map +1 -1
  83. package/dist/daemon/client.d.ts +99 -0
  84. package/dist/daemon/client.d.ts.map +1 -0
  85. package/dist/daemon/client.js +292 -0
  86. package/dist/daemon/client.js.map +1 -0
  87. package/dist/daemon/discovery.d.ts +50 -0
  88. package/dist/daemon/discovery.d.ts.map +1 -0
  89. package/dist/daemon/discovery.js +104 -0
  90. package/dist/daemon/discovery.js.map +1 -0
  91. package/dist/daemon/index.d.ts +16 -0
  92. package/dist/daemon/index.d.ts.map +1 -0
  93. package/dist/daemon/index.js +11 -0
  94. package/dist/daemon/index.js.map +1 -0
  95. package/dist/daemon/sandbox-api.d.ts +45 -0
  96. package/dist/daemon/sandbox-api.d.ts.map +1 -0
  97. package/dist/daemon/sandbox-api.js +74 -0
  98. package/dist/daemon/sandbox-api.js.map +1 -0
  99. package/dist/daemon/server.d.ts +65 -0
  100. package/dist/daemon/server.d.ts.map +1 -0
  101. package/dist/daemon/server.js +373 -0
  102. package/dist/daemon/server.js.map +1 -0
  103. package/dist/daemon/shared-kv.d.ts +81 -0
  104. package/dist/daemon/shared-kv.d.ts.map +1 -0
  105. package/dist/daemon/shared-kv.js +215 -0
  106. package/dist/daemon/shared-kv.js.map +1 -0
  107. package/dist/daemon/shared-lock.d.ts +71 -0
  108. package/dist/daemon/shared-lock.d.ts.map +1 -0
  109. package/dist/daemon/shared-lock.js +119 -0
  110. package/dist/daemon/shared-lock.js.map +1 -0
  111. package/dist/hub/mcp-hub.d.ts +23 -0
  112. package/dist/hub/mcp-hub.d.ts.map +1 -1
  113. package/dist/hub/mcp-hub.js +34 -1
  114. package/dist/hub/mcp-hub.js.map +1 -1
  115. package/dist/index.js +7 -0
  116. package/dist/index.js.map +1 -1
  117. package/dist/observability/anomaly.d.ts +67 -0
  118. package/dist/observability/anomaly.d.ts.map +1 -0
  119. package/dist/observability/anomaly.js +141 -0
  120. package/dist/observability/anomaly.js.map +1 -0
  121. package/dist/observability/cost-predictor.d.ts +49 -0
  122. package/dist/observability/cost-predictor.d.ts.map +1 -0
  123. package/dist/observability/cost-predictor.js +145 -0
  124. package/dist/observability/cost-predictor.js.map +1 -0
  125. package/dist/observability/hot-path.d.ts +49 -0
  126. package/dist/observability/hot-path.d.ts.map +1 -0
  127. package/dist/observability/hot-path.js +125 -0
  128. package/dist/observability/hot-path.js.map +1 -0
  129. package/dist/observability/index.d.ts +10 -0
  130. package/dist/observability/index.d.ts.map +1 -0
  131. package/dist/observability/index.js +10 -0
  132. package/dist/observability/index.js.map +1 -0
  133. package/dist/observability/replay.d.ts +104 -0
  134. package/dist/observability/replay.d.ts.map +1 -0
  135. package/dist/observability/replay.js +239 -0
  136. package/dist/observability/replay.js.map +1 -0
  137. package/dist/registry/built-in-recommendations.d.ts +54 -0
  138. package/dist/registry/built-in-recommendations.d.ts.map +1 -0
  139. package/dist/registry/built-in-recommendations.js +65 -0
  140. package/dist/registry/built-in-recommendations.js.map +1 -0
  141. package/dist/registry/events.d.ts +26 -0
  142. package/dist/registry/events.d.ts.map +1 -0
  143. package/dist/registry/events.js +22 -0
  144. package/dist/registry/events.js.map +1 -0
  145. package/dist/registry/index.d.ts +159 -0
  146. package/dist/registry/index.d.ts.map +1 -0
  147. package/dist/registry/index.js +12 -0
  148. package/dist/registry/index.js.map +1 -0
  149. package/dist/registry/registry.d.ts +87 -0
  150. package/dist/registry/registry.d.ts.map +1 -0
  151. package/dist/registry/registry.js +294 -0
  152. package/dist/registry/registry.js.map +1 -0
  153. package/dist/registry/snapshot.d.ts +42 -0
  154. package/dist/registry/snapshot.d.ts.map +1 -0
  155. package/dist/registry/snapshot.js +71 -0
  156. package/dist/registry/snapshot.js.map +1 -0
  157. package/dist/registry/typegen.d.ts +48 -0
  158. package/dist/registry/typegen.d.ts.map +1 -0
  159. package/dist/registry/typegen.js +200 -0
  160. package/dist/registry/typegen.js.map +1 -0
  161. package/dist/registry/validator.d.ts +23 -0
  162. package/dist/registry/validator.d.ts.map +1 -0
  163. package/dist/registry/validator.js +50 -0
  164. package/dist/registry/validator.js.map +1 -0
  165. package/dist/reliability/breaker.d.ts +57 -0
  166. package/dist/reliability/breaker.d.ts.map +1 -0
  167. package/dist/reliability/breaker.js +130 -0
  168. package/dist/reliability/breaker.js.map +1 -0
  169. package/dist/reliability/errors.d.ts +78 -0
  170. package/dist/reliability/errors.d.ts.map +1 -0
  171. package/dist/reliability/errors.js +160 -0
  172. package/dist/reliability/errors.js.map +1 -0
  173. package/dist/reliability/gateway.d.ts +88 -0
  174. package/dist/reliability/gateway.d.ts.map +1 -0
  175. package/dist/reliability/gateway.js +180 -0
  176. package/dist/reliability/gateway.js.map +1 -0
  177. package/dist/reliability/index.d.ts +20 -0
  178. package/dist/reliability/index.d.ts.map +1 -0
  179. package/dist/reliability/index.js +16 -0
  180. package/dist/reliability/index.js.map +1 -0
  181. package/dist/reliability/profile.d.ts +49 -0
  182. package/dist/reliability/profile.d.ts.map +1 -0
  183. package/dist/reliability/profile.js +58 -0
  184. package/dist/reliability/profile.js.map +1 -0
  185. package/dist/reliability/retry.d.ts +39 -0
  186. package/dist/reliability/retry.d.ts.map +1 -0
  187. package/dist/reliability/retry.js +51 -0
  188. package/dist/reliability/retry.js.map +1 -0
  189. package/dist/reliability/timeout.d.ts +34 -0
  190. package/dist/reliability/timeout.d.ts.map +1 -0
  191. package/dist/reliability/timeout.js +53 -0
  192. package/dist/reliability/timeout.js.map +1 -0
  193. package/dist/runtime/executor.d.ts.map +1 -1
  194. package/dist/runtime/executor.js +122 -14
  195. package/dist/runtime/executor.js.map +1 -1
  196. package/dist/runtime/findtool/embed.d.ts +28 -0
  197. package/dist/runtime/findtool/embed.d.ts.map +1 -0
  198. package/dist/runtime/findtool/embed.js +85 -0
  199. package/dist/runtime/findtool/embed.js.map +1 -0
  200. package/dist/runtime/findtool/index.d.ts +52 -0
  201. package/dist/runtime/findtool/index.d.ts.map +1 -0
  202. package/dist/runtime/findtool/index.js +78 -0
  203. package/dist/runtime/findtool/index.js.map +1 -0
  204. package/dist/runtime/findtool/vector-index.d.ts +53 -0
  205. package/dist/runtime/findtool/vector-index.d.ts.map +1 -0
  206. package/dist/runtime/findtool/vector-index.js +71 -0
  207. package/dist/runtime/findtool/vector-index.js.map +1 -0
  208. package/dist/runtime/helpers/budget.d.ts +27 -0
  209. package/dist/runtime/helpers/budget.d.ts.map +1 -0
  210. package/dist/runtime/helpers/budget.js +103 -0
  211. package/dist/runtime/helpers/budget.js.map +1 -0
  212. package/dist/runtime/helpers/compact.d.ts +32 -0
  213. package/dist/runtime/helpers/compact.d.ts.map +1 -0
  214. package/dist/runtime/helpers/compact.js +93 -0
  215. package/dist/runtime/helpers/compact.js.map +1 -0
  216. package/dist/runtime/helpers/delta.d.ts +45 -0
  217. package/dist/runtime/helpers/delta.d.ts.map +1 -0
  218. package/dist/runtime/helpers/delta.js +116 -0
  219. package/dist/runtime/helpers/delta.js.map +1 -0
  220. package/dist/runtime/helpers/index.d.ts +16 -0
  221. package/dist/runtime/helpers/index.d.ts.map +1 -0
  222. package/dist/runtime/helpers/index.js +13 -0
  223. package/dist/runtime/helpers/index.js.map +1 -0
  224. package/dist/runtime/helpers/summarize.d.ts +24 -0
  225. package/dist/runtime/helpers/summarize.d.ts.map +1 -0
  226. package/dist/runtime/helpers/summarize.js +124 -0
  227. package/dist/runtime/helpers/summarize.js.map +1 -0
  228. package/dist/runtime/helpers/worker-preload.d.ts +25 -0
  229. package/dist/runtime/helpers/worker-preload.d.ts.map +1 -0
  230. package/dist/runtime/helpers/worker-preload.js +223 -0
  231. package/dist/runtime/helpers/worker-preload.js.map +1 -0
  232. package/dist/runtime/index.d.ts +1 -0
  233. package/dist/runtime/index.d.ts.map +1 -1
  234. package/dist/runtime/index.js +1 -0
  235. package/dist/runtime/index.js.map +1 -1
  236. package/dist/runtime/pool/index.d.ts +11 -0
  237. package/dist/runtime/pool/index.d.ts.map +1 -0
  238. package/dist/runtime/pool/index.js +8 -0
  239. package/dist/runtime/pool/index.js.map +1 -0
  240. package/dist/runtime/pool/recycle.d.ts +44 -0
  241. package/dist/runtime/pool/recycle.d.ts.map +1 -0
  242. package/dist/runtime/pool/recycle.js +50 -0
  243. package/dist/runtime/pool/recycle.js.map +1 -0
  244. package/dist/runtime/pool/worker-pool.d.ts +77 -0
  245. package/dist/runtime/pool/worker-pool.d.ts.map +1 -0
  246. package/dist/runtime/pool/worker-pool.js +216 -0
  247. package/dist/runtime/pool/worker-pool.js.map +1 -0
  248. package/dist/runtime/pool/worker.d.ts +80 -0
  249. package/dist/runtime/pool/worker.d.ts.map +1 -0
  250. package/dist/runtime/pool/worker.js +324 -0
  251. package/dist/runtime/pool/worker.js.map +1 -0
  252. package/dist/server/mcp-server.d.ts +3 -0
  253. package/dist/server/mcp-server.d.ts.map +1 -1
  254. package/dist/server/mcp-server.js +457 -3
  255. package/dist/server/mcp-server.js.map +1 -1
  256. package/dist/server/passthrough-registrar.d.ts +123 -0
  257. package/dist/server/passthrough-registrar.d.ts.map +1 -0
  258. package/dist/server/passthrough-registrar.js +199 -0
  259. package/dist/server/passthrough-registrar.js.map +1 -0
  260. package/dist/skills/skills-engine.d.ts +9 -1
  261. package/dist/skills/skills-engine.d.ts.map +1 -1
  262. package/dist/skills/skills-engine.js +20 -3
  263. package/dist/skills/skills-engine.js.map +1 -1
  264. package/dist/utils/index.d.ts +1 -0
  265. package/dist/utils/index.d.ts.map +1 -1
  266. package/dist/utils/index.js +1 -0
  267. package/dist/utils/index.js.map +1 -1
  268. package/dist/utils/tokenize.d.ts +55 -0
  269. package/dist/utils/tokenize.d.ts.map +1 -0
  270. package/dist/utils/tokenize.js +205 -0
  271. package/dist/utils/tokenize.js.map +1 -0
  272. package/dist/version.d.ts +3 -3
  273. package/dist/version.d.ts.map +1 -1
  274. package/dist/version.js +3 -3
  275. package/dist/version.js.map +1 -1
  276. package/package.json +13 -3
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Backend Connection Pool
3
+ *
4
+ * Maintains persistent stdio connections to MCP backend servers, multiplexes
5
+ * JSON-RPC requests over the same channel, and respawns crashed backends
6
+ * within 1 second. Eliminates per-request spawn overhead.
7
+ *
8
+ * Design:
9
+ * - Each server gets [min, max] connections whose lifecycle is managed here
10
+ * - JSON-RPC multiplexing: requests tagged with a unique id; responses routed
11
+ * back to the correct in-flight caller via a pending-map
12
+ * - Idle timer: connections unused for `idleTimeoutMs` are gracefully closed
13
+ * - Crash recovery: `close` event triggers automatic respawn
14
+ *
15
+ * @module bridge/pool
16
+ */
17
+ import { EventEmitter } from 'node:events';
18
+ import type { ConnectionPoolConfig } from '../config/schema.js';
19
+ export interface PoolStats {
20
+ totalConnections: number;
21
+ idleConnections: number;
22
+ busyConnections: number;
23
+ serversTracked: number;
24
+ pendingAcquires: number;
25
+ }
26
+ /** Opaque handle returned by `acquire()`. Pass back to `release()`. */
27
+ export interface PooledConnection {
28
+ readonly id: string;
29
+ readonly serverKey: string;
30
+ /** Send a multiplexed JSON-RPC call; resolves with the parsed response. */
31
+ call(method: string, params?: unknown): Promise<unknown>;
32
+ }
33
+ /**
34
+ * Factory function that creates a new stdio channel to a backend.
35
+ * Returns a send function and a closer; delivers received lines via callback.
36
+ */
37
+ export type ConnectionFactory = (opts: {
38
+ onLine: (line: string) => void;
39
+ onClose: () => void;
40
+ onError: (err: Error) => void;
41
+ }) => {
42
+ write: (line: string) => boolean;
43
+ close: () => void;
44
+ };
45
+ /**
46
+ * A connection pool for MCP backend servers.
47
+ *
48
+ * Usage:
49
+ * ```ts
50
+ * pool.registerServer('my-server', factory);
51
+ * const conn = await pool.acquire('my-server');
52
+ * const result = await conn.call('tools/list');
53
+ * pool.release(conn);
54
+ * ```
55
+ */
56
+ export declare class ConnectionPool extends EventEmitter {
57
+ private readonly opts;
58
+ private readonly servers;
59
+ private isShuttingDown;
60
+ constructor(options?: ConnectionPoolConfig);
61
+ /**
62
+ * Register a backend server with its connection factory.
63
+ * Call this before `acquire()`. Pre-warms `minConnectionsPerServer`
64
+ * connections immediately.
65
+ */
66
+ registerServer(serverKey: string, factory: ConnectionFactory): void;
67
+ /**
68
+ * Acquire an idle connection for `serverKey`.
69
+ *
70
+ * If all connections are busy and count < max, spawns a new one.
71
+ * If at max, waits up to `acquireTimeoutMs` for a release.
72
+ */
73
+ acquire(serverKey: string): Promise<PooledConnection>;
74
+ /**
75
+ * Return a connection to the pool.
76
+ * Idle timer is (re)started; if waiters are queued, hands off immediately.
77
+ */
78
+ release(connection: PooledConnection): void;
79
+ /** Gracefully drain all connections and stop accepting new ones. */
80
+ shutdown(): Promise<void>;
81
+ /** Snapshot of pool health metrics. */
82
+ stats(): PoolStats;
83
+ private _findIdle;
84
+ private _markBusy;
85
+ private _toPublic;
86
+ private _rpcCall;
87
+ private _spawnConnection;
88
+ private _handleLine;
89
+ private _handleClose;
90
+ private _handleError;
91
+ private _startIdleTimer;
92
+ private _closeInternal;
93
+ private _drainWaiters;
94
+ }
95
+ //# sourceMappingURL=pool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pool.d.ts","sourceRoot":"","sources":["../../src/bridge/pool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAMhE,MAAM,WAAW,SAAS;IACxB,gBAAgB,EAAE,MAAM,CAAC;IACzB,eAAe,EAAE,MAAM,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,uEAAuE;AACvE,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,2EAA2E;IAC3E,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC1D;AA6CD;;;GAGG;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,IAAI,EAAE;IACrC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,OAAO,EAAE,CAAC,GAAG,EAAE,KAAK,KAAK,IAAI,CAAC;CAC/B,KAAK;IACJ,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;IACjC,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB,CAAC;AAaF;;;;;;;;;;GAUG;AACH,qBAAa,cAAe,SAAQ,YAAY;IAC9C,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAiC;IACtD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAuC;IAC/D,OAAO,CAAC,cAAc,CAAS;gBAEnB,OAAO,GAAE,oBAAyB;IAK9C;;;;OAIG;IACH,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,iBAAiB,GAAG,IAAI;IAoBnE;;;;;OAKG;IACG,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAuC3D;;;OAGG;IACH,OAAO,CAAC,UAAU,EAAE,gBAAgB,GAAG,IAAI;IAuB3C,oEAAoE;IAC9D,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAqB/B,uCAAuC;IACvC,KAAK,IAAI,SAAS;IA6BlB,OAAO,CAAC,SAAS;IAOjB,OAAO,CAAC,SAAS;IAUjB,OAAO,CAAC,SAAS;IAQjB,OAAO,CAAC,QAAQ;YAkBF,gBAAgB;IAiD9B,OAAO,CAAC,WAAW;IAkCnB,OAAO,CAAC,YAAY;IA6CpB,OAAO,CAAC,YAAY;IAKpB,OAAO,CAAC,eAAe;IAgBvB,OAAO,CAAC,cAAc;IAsBtB,OAAO,CAAC,aAAa;CAUtB"}
@@ -0,0 +1,384 @@
1
+ /**
2
+ * Backend Connection Pool
3
+ *
4
+ * Maintains persistent stdio connections to MCP backend servers, multiplexes
5
+ * JSON-RPC requests over the same channel, and respawns crashed backends
6
+ * within 1 second. Eliminates per-request spawn overhead.
7
+ *
8
+ * Design:
9
+ * - Each server gets [min, max] connections whose lifecycle is managed here
10
+ * - JSON-RPC multiplexing: requests tagged with a unique id; responses routed
11
+ * back to the correct in-flight caller via a pending-map
12
+ * - Idle timer: connections unused for `idleTimeoutMs` are gracefully closed
13
+ * - Crash recovery: `close` event triggers automatic respawn
14
+ *
15
+ * @module bridge/pool
16
+ */
17
+ import { EventEmitter } from 'node:events';
18
+ import { logger } from '../utils/index.js';
19
+ // ─────────────────────────────────────────────────────────────────────────────
20
+ // ConnectionPool
21
+ // ─────────────────────────────────────────────────────────────────────────────
22
+ const DEFAULT_OPTIONS = {
23
+ minConnectionsPerServer: 1,
24
+ maxConnectionsPerServer: 4,
25
+ idleTimeoutMs: 300_000,
26
+ acquireTimeoutMs: 5_000,
27
+ };
28
+ /**
29
+ * A connection pool for MCP backend servers.
30
+ *
31
+ * Usage:
32
+ * ```ts
33
+ * pool.registerServer('my-server', factory);
34
+ * const conn = await pool.acquire('my-server');
35
+ * const result = await conn.call('tools/list');
36
+ * pool.release(conn);
37
+ * ```
38
+ */
39
+ export class ConnectionPool extends EventEmitter {
40
+ opts;
41
+ servers = new Map();
42
+ isShuttingDown = false;
43
+ constructor(options = {}) {
44
+ super();
45
+ this.opts = { ...DEFAULT_OPTIONS, ...options };
46
+ }
47
+ /**
48
+ * Register a backend server with its connection factory.
49
+ * Call this before `acquire()`. Pre-warms `minConnectionsPerServer`
50
+ * connections immediately.
51
+ */
52
+ registerServer(serverKey, factory) {
53
+ if (this.servers.has(serverKey))
54
+ return;
55
+ const entry = {
56
+ key: serverKey,
57
+ connections: new Map(),
58
+ waiting: [],
59
+ factory,
60
+ spawning: 0,
61
+ };
62
+ this.servers.set(serverKey, entry);
63
+ // Pre-warm minimum connections
64
+ for (let i = 0; i < this.opts.minConnectionsPerServer; i++) {
65
+ this._spawnConnection(entry).catch((err) => {
66
+ logger.warn('ConnectionPool: pre-warm spawn failed', { serverKey, err: String(err) });
67
+ });
68
+ }
69
+ }
70
+ /**
71
+ * Acquire an idle connection for `serverKey`.
72
+ *
73
+ * If all connections are busy and count < max, spawns a new one.
74
+ * If at max, waits up to `acquireTimeoutMs` for a release.
75
+ */
76
+ async acquire(serverKey) {
77
+ if (this.isShuttingDown) {
78
+ throw new Error(`ConnectionPool is shutting down`);
79
+ }
80
+ const entry = this.servers.get(serverKey);
81
+ if (!entry) {
82
+ throw new Error(`ConnectionPool: unknown server "${serverKey}". Call registerServer() first.`);
83
+ }
84
+ // Try to find an idle connection
85
+ const idle = this._findIdle(entry);
86
+ if (idle) {
87
+ return this._markBusy(idle);
88
+ }
89
+ // Spawn a new connection if under max
90
+ const totalActive = entry.connections.size + entry.spawning;
91
+ if (totalActive < this.opts.maxConnectionsPerServer) {
92
+ const conn = await this._spawnConnection(entry);
93
+ return this._markBusy(conn);
94
+ }
95
+ // All at max — wait for a release
96
+ return new Promise((resolve, reject) => {
97
+ const timer = setTimeout(() => {
98
+ const idx = entry.waiting.indexOf(waiter);
99
+ if (idx !== -1)
100
+ entry.waiting.splice(idx, 1);
101
+ reject(new Error(`ConnectionPool: acquire timeout after ${this.opts.acquireTimeoutMs}ms for "${serverKey}"`));
102
+ }, this.opts.acquireTimeoutMs);
103
+ // Allow the timer to be GC'd without blocking Node exit
104
+ if (timer.unref)
105
+ timer.unref();
106
+ const waiter = { resolve, reject, timer };
107
+ entry.waiting.push(waiter);
108
+ });
109
+ }
110
+ /**
111
+ * Return a connection to the pool.
112
+ * Idle timer is (re)started; if waiters are queued, hands off immediately.
113
+ */
114
+ release(connection) {
115
+ const entry = this.servers.get(connection.serverKey);
116
+ if (!entry)
117
+ return;
118
+ const internal = entry.connections.get(connection.id);
119
+ if (!internal || internal.closed)
120
+ return;
121
+ internal.busy = false;
122
+ // Drain waiting queue first
123
+ if (entry.waiting.length > 0) {
124
+ const waiter = entry.waiting.shift();
125
+ clearTimeout(waiter.timer);
126
+ // Mark busy synchronously before handing off
127
+ internal.busy = true;
128
+ waiter.resolve(this._toPublic(internal));
129
+ return;
130
+ }
131
+ // Start idle timer
132
+ this._startIdleTimer(entry, internal);
133
+ }
134
+ /** Gracefully drain all connections and stop accepting new ones. */
135
+ async shutdown() {
136
+ this.isShuttingDown = true;
137
+ for (const entry of this.servers.values()) {
138
+ // Reject all waiting acquires
139
+ for (const waiter of entry.waiting) {
140
+ clearTimeout(waiter.timer);
141
+ waiter.reject(new Error('ConnectionPool shut down'));
142
+ }
143
+ entry.waiting.length = 0;
144
+ // Close all connections
145
+ for (const conn of entry.connections.values()) {
146
+ this._closeInternal(conn);
147
+ }
148
+ }
149
+ this.servers.clear();
150
+ logger.info('ConnectionPool: shut down complete');
151
+ }
152
+ /** Snapshot of pool health metrics. */
153
+ stats() {
154
+ let total = 0;
155
+ let idle = 0;
156
+ let busy = 0;
157
+ let pending = 0;
158
+ for (const entry of this.servers.values()) {
159
+ for (const conn of entry.connections.values()) {
160
+ if (conn.closed)
161
+ continue;
162
+ total++;
163
+ if (conn.busy)
164
+ busy++;
165
+ else
166
+ idle++;
167
+ }
168
+ pending += entry.waiting.length;
169
+ }
170
+ return {
171
+ totalConnections: total,
172
+ idleConnections: idle,
173
+ busyConnections: busy,
174
+ serversTracked: this.servers.size,
175
+ pendingAcquires: pending,
176
+ };
177
+ }
178
+ // ───────────────────────────────────────────────────────────────────────────
179
+ // Private helpers
180
+ // ───────────────────────────────────────────────────────────────────────────
181
+ _findIdle(entry) {
182
+ for (const conn of entry.connections.values()) {
183
+ if (!conn.busy && !conn.closed)
184
+ return conn;
185
+ }
186
+ return undefined;
187
+ }
188
+ _markBusy(conn) {
189
+ conn.busy = true;
190
+ // Cancel idle timer if active
191
+ if (conn.idleTimer) {
192
+ clearTimeout(conn.idleTimer);
193
+ conn.idleTimer = null;
194
+ }
195
+ return this._toPublic(conn);
196
+ }
197
+ _toPublic(internal) {
198
+ return {
199
+ id: internal.id,
200
+ serverKey: internal.serverKey,
201
+ call: (method, params) => this._rpcCall(internal, method, params),
202
+ };
203
+ }
204
+ _rpcCall(conn, method, params) {
205
+ if (conn.closed || !conn.writeLine) {
206
+ return Promise.reject(new Error(`Connection ${conn.id} is closed`));
207
+ }
208
+ const id = conn.nextRequestId++;
209
+ const message = JSON.stringify({ jsonrpc: '2.0', id, method, params: params ?? {} });
210
+ return new Promise((resolve, reject) => {
211
+ conn.pending.set(id, { resolve, reject });
212
+ const ok = conn.writeLine(message + '\n');
213
+ if (!ok) {
214
+ conn.pending.delete(id);
215
+ reject(new Error(`Write failed on connection ${conn.id}`));
216
+ }
217
+ });
218
+ }
219
+ async _spawnConnection(entry) {
220
+ entry.spawning++;
221
+ const id = `${entry.key}-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`;
222
+ const internal = {
223
+ id,
224
+ serverKey: entry.key,
225
+ busy: false,
226
+ idleTimer: null,
227
+ pending: new Map(),
228
+ nextRequestId: 1,
229
+ lineBuffer: '',
230
+ writeLine: null,
231
+ close: () => { },
232
+ closed: false,
233
+ createdAt: Date.now(),
234
+ };
235
+ return new Promise((resolve, reject) => {
236
+ let resolved = false;
237
+ const transport = entry.factory({
238
+ onLine: (line) => this._handleLine(internal, line),
239
+ onClose: () => this._handleClose(entry, internal),
240
+ onError: (err) => {
241
+ if (!resolved) {
242
+ resolved = true;
243
+ entry.spawning--;
244
+ entry.connections.delete(id);
245
+ reject(err);
246
+ }
247
+ else {
248
+ this._handleError(entry, internal, err);
249
+ }
250
+ },
251
+ });
252
+ internal.writeLine = transport.write;
253
+ internal.close = transport.close;
254
+ entry.connections.set(id, internal);
255
+ entry.spawning--;
256
+ resolved = true;
257
+ logger.debug('ConnectionPool: spawned connection', { id, server: entry.key });
258
+ resolve(internal);
259
+ });
260
+ }
261
+ _handleLine(conn, raw) {
262
+ // Accumulate partial lines
263
+ conn.lineBuffer += raw;
264
+ // Process all complete newline-terminated JSON objects
265
+ let nl;
266
+ while ((nl = conn.lineBuffer.indexOf('\n')) !== -1) {
267
+ const line = conn.lineBuffer.slice(0, nl).trim();
268
+ conn.lineBuffer = conn.lineBuffer.slice(nl + 1);
269
+ if (!line)
270
+ continue;
271
+ let msg;
272
+ try {
273
+ msg = JSON.parse(line);
274
+ }
275
+ catch {
276
+ logger.warn('ConnectionPool: unparseable line from backend', { conn: conn.id, line: line.slice(0, 200) });
277
+ continue;
278
+ }
279
+ if (msg.id !== undefined) {
280
+ const pending = conn.pending.get(msg.id);
281
+ if (pending) {
282
+ conn.pending.delete(msg.id);
283
+ if (msg.error) {
284
+ pending.reject(new Error(msg.error.message ?? 'RPC error'));
285
+ }
286
+ else {
287
+ pending.resolve(msg.result);
288
+ }
289
+ }
290
+ }
291
+ }
292
+ }
293
+ _handleClose(entry, conn) {
294
+ if (conn.closed)
295
+ return;
296
+ conn.closed = true;
297
+ conn.writeLine = null;
298
+ // Reject all in-flight calls
299
+ for (const [, pending] of conn.pending) {
300
+ pending.reject(new Error(`Connection ${conn.id} to "${entry.key}" closed unexpectedly`));
301
+ }
302
+ conn.pending.clear();
303
+ if (conn.idleTimer) {
304
+ clearTimeout(conn.idleTimer);
305
+ conn.idleTimer = null;
306
+ }
307
+ entry.connections.delete(conn.id);
308
+ logger.warn('ConnectionPool: connection closed', { id: conn.id, server: entry.key });
309
+ if (this.isShuttingDown)
310
+ return;
311
+ // Respawn to maintain minimum floor
312
+ const activeCount = entry.connections.size + entry.spawning;
313
+ if (activeCount < this.opts.minConnectionsPerServer) {
314
+ setTimeout(() => {
315
+ if (!this.isShuttingDown) {
316
+ this._spawnConnection(entry)
317
+ .then((newConn) => {
318
+ logger.info('ConnectionPool: respawned connection after crash', {
319
+ newId: newConn.id,
320
+ server: entry.key,
321
+ });
322
+ // Drain any waiters that accumulated during the crash
323
+ this._drainWaiters(entry);
324
+ })
325
+ .catch((err) => {
326
+ logger.error('ConnectionPool: respawn failed', { server: entry.key, err: String(err) });
327
+ });
328
+ }
329
+ }, 0).unref?.();
330
+ }
331
+ this.emit('connectionClosed', entry.key, conn.id);
332
+ }
333
+ _handleError(entry, conn, err) {
334
+ logger.error('ConnectionPool: connection error', { id: conn.id, server: entry.key, err: err.message });
335
+ this._handleClose(entry, conn);
336
+ }
337
+ _startIdleTimer(entry, conn) {
338
+ if (conn.idleTimer)
339
+ clearTimeout(conn.idleTimer);
340
+ conn.idleTimer = setTimeout(() => {
341
+ const currentCount = entry.connections.size;
342
+ if (!conn.busy && currentCount > this.opts.minConnectionsPerServer) {
343
+ logger.debug('ConnectionPool: closing idle connection', { id: conn.id, server: entry.key });
344
+ this._closeInternal(conn);
345
+ entry.connections.delete(conn.id);
346
+ }
347
+ }, this.opts.idleTimeoutMs);
348
+ // Do not block Node.js exit for idle timers
349
+ if (conn.idleTimer.unref)
350
+ conn.idleTimer.unref();
351
+ }
352
+ _closeInternal(conn) {
353
+ if (conn.closed)
354
+ return;
355
+ conn.closed = true;
356
+ conn.writeLine = null;
357
+ for (const [, pending] of conn.pending) {
358
+ pending.reject(new Error(`Connection ${conn.id} closed`));
359
+ }
360
+ conn.pending.clear();
361
+ if (conn.idleTimer) {
362
+ clearTimeout(conn.idleTimer);
363
+ conn.idleTimer = null;
364
+ }
365
+ try {
366
+ conn.close();
367
+ }
368
+ catch {
369
+ // Ignore close errors
370
+ }
371
+ }
372
+ _drainWaiters(entry) {
373
+ while (entry.waiting.length > 0) {
374
+ const idle = this._findIdle(entry);
375
+ if (!idle)
376
+ break;
377
+ const waiter = entry.waiting.shift();
378
+ clearTimeout(waiter.timer);
379
+ idle.busy = true;
380
+ waiter.resolve(this._toPublic(idle));
381
+ }
382
+ }
383
+ }
384
+ //# sourceMappingURL=pool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pool.js","sourceRoot":"","sources":["../../src/bridge/pool.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,64 @@
1
+ /**
2
+ * CacheLayer — three-tier cache composition (memory LRU + disk CBOR + delta).
3
+ *
4
+ * Call flow:
5
+ * get(server, tool, args)
6
+ * → memory LRU hit? → return CacheHit (source: 'memory')
7
+ * → disk hit? → promote to memory, return CacheHit (source: 'disk')
8
+ * → miss → return null (caller must fetch from backend)
9
+ *
10
+ * Stale-while-revalidate (SWR):
11
+ * All staleness decisions are made here, not in DiskCache, so that
12
+ * vi.useFakeTimers() in tests correctly affects TTL checks at all tiers.
13
+ *
14
+ * Bridge wiring order (per spec):
15
+ * cache check → cache miss → reliability gateway (Agent C) → backend
16
+ *
17
+ * @module cache/cache
18
+ */
19
+ import type { CacheHit, CacheStats, CacheLayerOptions, DeltaResult } from './index.js';
20
+ export interface ExtendedCacheHit extends CacheHit {
21
+ needsRevalidation?: boolean;
22
+ }
23
+ export declare class CacheLayer {
24
+ private lru;
25
+ private disk;
26
+ private registry;
27
+ private options;
28
+ private unsubscribe;
29
+ private diskMisses;
30
+ private ttlMap;
31
+ /** Keys currently being background-revalidated; prevents SWR thundering herd. */
32
+ private revalidating;
33
+ constructor(options: CacheLayerOptions);
34
+ get(server: string, tool: string, args: unknown): Promise<ExtendedCacheHit | null>;
35
+ set(server: string, tool: string, args: unknown, result: unknown, options?: {
36
+ ttl?: number;
37
+ }): Promise<void>;
38
+ invalidate(server: string, pattern?: string): Promise<number>;
39
+ delta(server: string, tool: string, args: unknown, current: unknown): Promise<DeltaResult>;
40
+ stats(): CacheStats;
41
+ clear(): Promise<void>;
42
+ wouldCache(server: string, tool: string): boolean;
43
+ /**
44
+ * Deduplicated background revalidation helper for stale-while-revalidate.
45
+ *
46
+ * Marks the cache key as being revalidated so subsequent concurrent `get()`
47
+ * calls that would also see `needsRevalidation: true` get `false` instead,
48
+ * preventing a thundering herd of parallel refreshes.
49
+ *
50
+ * The key is removed from the revalidating set on completion (success or
51
+ * failure), allowing a future `get()` to schedule a fresh revalidation if
52
+ * the entry is still stale at that point.
53
+ *
54
+ * @param server MCP server name.
55
+ * @param tool Tool name.
56
+ * @param args Original call arguments (used to build the cache key).
57
+ * @param fetchFn Async function that calls the backend and returns the fresh result.
58
+ * @returns A promise that resolves when the background refresh completes.
59
+ * Callers should `.catch()` the returned promise to handle errors.
60
+ */
61
+ refreshInBackground(server: string, tool: string, args: unknown, fetchFn: () => Promise<unknown>): Promise<void>;
62
+ destroy(): void;
63
+ }
64
+ //# sourceMappingURL=cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../src/cache/cache.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAUH,OAAO,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEvF,MAAM,WAAW,gBAAiB,SAAQ,QAAQ;IAChD,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED,qBAAa,UAAU;IACrB,OAAO,CAAC,GAAG,CAAY;IACvB,OAAO,CAAC,IAAI,CAAY;IACxB,OAAO,CAAC,QAAQ,CAAe;IAC/B,OAAO,CAAC,OAAO,CAA8B;IAC7C,OAAO,CAAC,WAAW,CAA6B;IAChD,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,MAAM,CAA6B;IAC3C,iFAAiF;IACjF,OAAO,CAAC,YAAY,CAAqB;gBAE7B,OAAO,EAAE,iBAAiB;IAgChC,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC;IA0DlF,GAAG,CACP,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,OAAO,EACb,MAAM,EAAE,OAAO,EACf,OAAO,CAAC,EAAE;QAAE,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,GACzB,OAAO,CAAC,IAAI,CAAC;IAkBV,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAO7D,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,WAAW,CAAC;IAMhG,KAAK,IAAI,UAAU;IAab,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ5B,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO;IAKjD;;;;;;;;;;;;;;;;;OAiBG;IACH,mBAAmB,CACjB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,OAAO,EACb,OAAO,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,GAC9B,OAAO,CAAC,IAAI,CAAC;IAqBhB,OAAO,IAAI,IAAI;CAMhB"}