@darkiceinteractive/mcp-conductor 1.1.0 → 3.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (293) 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 +65 -1
  7. package/dist/bridge/http-server.d.ts.map +1 -1
  8. package/dist/bridge/http-server.js +192 -7
  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/bridge/session-registry.d.ts +64 -0
  19. package/dist/bridge/session-registry.d.ts.map +1 -0
  20. package/dist/bridge/session-registry.js +124 -0
  21. package/dist/bridge/session-registry.js.map +1 -0
  22. package/dist/cache/cache.d.ts +43 -0
  23. package/dist/cache/cache.d.ts.map +1 -0
  24. package/dist/cache/cache.js +167 -0
  25. package/dist/cache/cache.js.map +1 -0
  26. package/dist/cache/delta.d.ts +32 -0
  27. package/dist/cache/delta.d.ts.map +1 -0
  28. package/dist/cache/delta.js +131 -0
  29. package/dist/cache/delta.js.map +1 -0
  30. package/dist/cache/disk.d.ts +65 -0
  31. package/dist/cache/disk.d.ts.map +1 -0
  32. package/dist/cache/disk.js +238 -0
  33. package/dist/cache/disk.js.map +1 -0
  34. package/dist/cache/index.d.ts +53 -0
  35. package/dist/cache/index.d.ts.map +1 -0
  36. package/dist/cache/index.js +12 -0
  37. package/dist/cache/index.js.map +1 -0
  38. package/dist/cache/key.d.ts +44 -0
  39. package/dist/cache/key.d.ts.map +1 -0
  40. package/dist/cache/key.js +83 -0
  41. package/dist/cache/key.js.map +1 -0
  42. package/dist/cache/lru.d.ts +57 -0
  43. package/dist/cache/lru.d.ts.map +1 -0
  44. package/dist/cache/lru.js +112 -0
  45. package/dist/cache/lru.js.map +1 -0
  46. package/dist/cache/policy.d.ts +34 -0
  47. package/dist/cache/policy.d.ts.map +1 -0
  48. package/dist/cache/policy.js +95 -0
  49. package/dist/cache/policy.js.map +1 -0
  50. package/dist/cli/commands/doctor.d.ts +33 -0
  51. package/dist/cli/commands/doctor.d.ts.map +1 -0
  52. package/dist/cli/commands/doctor.js +135 -0
  53. package/dist/cli/commands/doctor.js.map +1 -0
  54. package/dist/cli/commands/export-servers.d.ts +22 -0
  55. package/dist/cli/commands/export-servers.d.ts.map +1 -0
  56. package/dist/cli/commands/export-servers.js +45 -0
  57. package/dist/cli/commands/export-servers.js.map +1 -0
  58. package/dist/cli/commands/import-servers.d.ts +57 -0
  59. package/dist/cli/commands/import-servers.d.ts.map +1 -0
  60. package/dist/cli/commands/import-servers.js +137 -0
  61. package/dist/cli/commands/import-servers.js.map +1 -0
  62. package/dist/cli/commands/routing.d.ts +34 -0
  63. package/dist/cli/commands/routing.d.ts.map +1 -0
  64. package/dist/cli/commands/routing.js +60 -0
  65. package/dist/cli/commands/routing.js.map +1 -0
  66. package/dist/cli/commands/test-server.d.ts +34 -0
  67. package/dist/cli/commands/test-server.d.ts.map +1 -0
  68. package/dist/cli/commands/test-server.js +86 -0
  69. package/dist/cli/commands/test-server.js.map +1 -0
  70. package/dist/cli/daemon.d.ts +60 -0
  71. package/dist/cli/daemon.d.ts.map +1 -0
  72. package/dist/cli/daemon.js +244 -0
  73. package/dist/cli/daemon.js.map +1 -0
  74. package/dist/cli/replay.d.ts +16 -0
  75. package/dist/cli/replay.d.ts.map +1 -0
  76. package/dist/cli/replay.js +89 -0
  77. package/dist/cli/replay.js.map +1 -0
  78. package/dist/cli/wizard/setup.d.ts +12 -0
  79. package/dist/cli/wizard/setup.d.ts.map +1 -0
  80. package/dist/cli/wizard/setup.js +71 -0
  81. package/dist/cli/wizard/setup.js.map +1 -0
  82. package/dist/config/defaults.d.ts +10 -0
  83. package/dist/config/defaults.d.ts.map +1 -1
  84. package/dist/config/defaults.js +14 -1
  85. package/dist/config/defaults.js.map +1 -1
  86. package/dist/config/schema.d.ts +34 -0
  87. package/dist/config/schema.d.ts.map +1 -1
  88. package/dist/daemon/client.d.ts +97 -0
  89. package/dist/daemon/client.d.ts.map +1 -0
  90. package/dist/daemon/client.js +279 -0
  91. package/dist/daemon/client.js.map +1 -0
  92. package/dist/daemon/discovery.d.ts +50 -0
  93. package/dist/daemon/discovery.d.ts.map +1 -0
  94. package/dist/daemon/discovery.js +104 -0
  95. package/dist/daemon/discovery.js.map +1 -0
  96. package/dist/daemon/index.d.ts +16 -0
  97. package/dist/daemon/index.d.ts.map +1 -0
  98. package/dist/daemon/index.js +11 -0
  99. package/dist/daemon/index.js.map +1 -0
  100. package/dist/daemon/sandbox-api.d.ts +45 -0
  101. package/dist/daemon/sandbox-api.d.ts.map +1 -0
  102. package/dist/daemon/sandbox-api.js +74 -0
  103. package/dist/daemon/sandbox-api.js.map +1 -0
  104. package/dist/daemon/server.d.ts +65 -0
  105. package/dist/daemon/server.d.ts.map +1 -0
  106. package/dist/daemon/server.js +351 -0
  107. package/dist/daemon/server.js.map +1 -0
  108. package/dist/daemon/shared-kv.d.ts +81 -0
  109. package/dist/daemon/shared-kv.d.ts.map +1 -0
  110. package/dist/daemon/shared-kv.js +215 -0
  111. package/dist/daemon/shared-kv.js.map +1 -0
  112. package/dist/daemon/shared-lock.d.ts +71 -0
  113. package/dist/daemon/shared-lock.d.ts.map +1 -0
  114. package/dist/daemon/shared-lock.js +119 -0
  115. package/dist/daemon/shared-lock.js.map +1 -0
  116. package/dist/hub/mcp-hub.d.ts +23 -0
  117. package/dist/hub/mcp-hub.d.ts.map +1 -1
  118. package/dist/hub/mcp-hub.js +34 -1
  119. package/dist/hub/mcp-hub.js.map +1 -1
  120. package/dist/index.js +19 -0
  121. package/dist/index.js.map +1 -1
  122. package/dist/observability/anomaly.d.ts +67 -0
  123. package/dist/observability/anomaly.d.ts.map +1 -0
  124. package/dist/observability/anomaly.js +141 -0
  125. package/dist/observability/anomaly.js.map +1 -0
  126. package/dist/observability/cost-predictor.d.ts +49 -0
  127. package/dist/observability/cost-predictor.d.ts.map +1 -0
  128. package/dist/observability/cost-predictor.js +145 -0
  129. package/dist/observability/cost-predictor.js.map +1 -0
  130. package/dist/observability/hot-path.d.ts +49 -0
  131. package/dist/observability/hot-path.d.ts.map +1 -0
  132. package/dist/observability/hot-path.js +125 -0
  133. package/dist/observability/hot-path.js.map +1 -0
  134. package/dist/observability/index.d.ts +10 -0
  135. package/dist/observability/index.d.ts.map +1 -0
  136. package/dist/observability/index.js +10 -0
  137. package/dist/observability/index.js.map +1 -0
  138. package/dist/observability/replay.d.ts +104 -0
  139. package/dist/observability/replay.d.ts.map +1 -0
  140. package/dist/observability/replay.js +239 -0
  141. package/dist/observability/replay.js.map +1 -0
  142. package/dist/registry/built-in-recommendations.d.ts +54 -0
  143. package/dist/registry/built-in-recommendations.d.ts.map +1 -0
  144. package/dist/registry/built-in-recommendations.js +65 -0
  145. package/dist/registry/built-in-recommendations.js.map +1 -0
  146. package/dist/registry/events.d.ts +26 -0
  147. package/dist/registry/events.d.ts.map +1 -0
  148. package/dist/registry/events.js +22 -0
  149. package/dist/registry/events.js.map +1 -0
  150. package/dist/registry/index.d.ts +159 -0
  151. package/dist/registry/index.d.ts.map +1 -0
  152. package/dist/registry/index.js +12 -0
  153. package/dist/registry/index.js.map +1 -0
  154. package/dist/registry/registry.d.ts +87 -0
  155. package/dist/registry/registry.d.ts.map +1 -0
  156. package/dist/registry/registry.js +294 -0
  157. package/dist/registry/registry.js.map +1 -0
  158. package/dist/registry/snapshot.d.ts +42 -0
  159. package/dist/registry/snapshot.d.ts.map +1 -0
  160. package/dist/registry/snapshot.js +71 -0
  161. package/dist/registry/snapshot.js.map +1 -0
  162. package/dist/registry/typegen.d.ts +48 -0
  163. package/dist/registry/typegen.d.ts.map +1 -0
  164. package/dist/registry/typegen.js +200 -0
  165. package/dist/registry/typegen.js.map +1 -0
  166. package/dist/registry/validator.d.ts +23 -0
  167. package/dist/registry/validator.d.ts.map +1 -0
  168. package/dist/registry/validator.js +50 -0
  169. package/dist/registry/validator.js.map +1 -0
  170. package/dist/reliability/breaker.d.ts +57 -0
  171. package/dist/reliability/breaker.d.ts.map +1 -0
  172. package/dist/reliability/breaker.js +130 -0
  173. package/dist/reliability/breaker.js.map +1 -0
  174. package/dist/reliability/errors.d.ts +78 -0
  175. package/dist/reliability/errors.d.ts.map +1 -0
  176. package/dist/reliability/errors.js +160 -0
  177. package/dist/reliability/errors.js.map +1 -0
  178. package/dist/reliability/gateway.d.ts +88 -0
  179. package/dist/reliability/gateway.d.ts.map +1 -0
  180. package/dist/reliability/gateway.js +180 -0
  181. package/dist/reliability/gateway.js.map +1 -0
  182. package/dist/reliability/index.d.ts +20 -0
  183. package/dist/reliability/index.d.ts.map +1 -0
  184. package/dist/reliability/index.js +16 -0
  185. package/dist/reliability/index.js.map +1 -0
  186. package/dist/reliability/profile.d.ts +49 -0
  187. package/dist/reliability/profile.d.ts.map +1 -0
  188. package/dist/reliability/profile.js +58 -0
  189. package/dist/reliability/profile.js.map +1 -0
  190. package/dist/reliability/retry.d.ts +39 -0
  191. package/dist/reliability/retry.d.ts.map +1 -0
  192. package/dist/reliability/retry.js +51 -0
  193. package/dist/reliability/retry.js.map +1 -0
  194. package/dist/reliability/timeout.d.ts +34 -0
  195. package/dist/reliability/timeout.d.ts.map +1 -0
  196. package/dist/reliability/timeout.js +53 -0
  197. package/dist/reliability/timeout.js.map +1 -0
  198. package/dist/runtime/executor.d.ts +12 -0
  199. package/dist/runtime/executor.d.ts.map +1 -1
  200. package/dist/runtime/executor.js +148 -16
  201. package/dist/runtime/executor.js.map +1 -1
  202. package/dist/runtime/findtool/embed.d.ts +28 -0
  203. package/dist/runtime/findtool/embed.d.ts.map +1 -0
  204. package/dist/runtime/findtool/embed.js +85 -0
  205. package/dist/runtime/findtool/embed.js.map +1 -0
  206. package/dist/runtime/findtool/index.d.ts +52 -0
  207. package/dist/runtime/findtool/index.d.ts.map +1 -0
  208. package/dist/runtime/findtool/index.js +78 -0
  209. package/dist/runtime/findtool/index.js.map +1 -0
  210. package/dist/runtime/findtool/vector-index.d.ts +53 -0
  211. package/dist/runtime/findtool/vector-index.d.ts.map +1 -0
  212. package/dist/runtime/findtool/vector-index.js +71 -0
  213. package/dist/runtime/findtool/vector-index.js.map +1 -0
  214. package/dist/runtime/helpers/budget.d.ts +27 -0
  215. package/dist/runtime/helpers/budget.d.ts.map +1 -0
  216. package/dist/runtime/helpers/budget.js +103 -0
  217. package/dist/runtime/helpers/budget.js.map +1 -0
  218. package/dist/runtime/helpers/compact.d.ts +32 -0
  219. package/dist/runtime/helpers/compact.d.ts.map +1 -0
  220. package/dist/runtime/helpers/compact.js +93 -0
  221. package/dist/runtime/helpers/compact.js.map +1 -0
  222. package/dist/runtime/helpers/delta.d.ts +45 -0
  223. package/dist/runtime/helpers/delta.d.ts.map +1 -0
  224. package/dist/runtime/helpers/delta.js +116 -0
  225. package/dist/runtime/helpers/delta.js.map +1 -0
  226. package/dist/runtime/helpers/index.d.ts +16 -0
  227. package/dist/runtime/helpers/index.d.ts.map +1 -0
  228. package/dist/runtime/helpers/index.js +13 -0
  229. package/dist/runtime/helpers/index.js.map +1 -0
  230. package/dist/runtime/helpers/summarize.d.ts +24 -0
  231. package/dist/runtime/helpers/summarize.d.ts.map +1 -0
  232. package/dist/runtime/helpers/summarize.js +124 -0
  233. package/dist/runtime/helpers/summarize.js.map +1 -0
  234. package/dist/runtime/helpers/worker-preload.d.ts +25 -0
  235. package/dist/runtime/helpers/worker-preload.d.ts.map +1 -0
  236. package/dist/runtime/helpers/worker-preload.js +223 -0
  237. package/dist/runtime/helpers/worker-preload.js.map +1 -0
  238. package/dist/runtime/index.d.ts +1 -0
  239. package/dist/runtime/index.d.ts.map +1 -1
  240. package/dist/runtime/index.js +1 -0
  241. package/dist/runtime/index.js.map +1 -1
  242. package/dist/runtime/pool/index.d.ts +11 -0
  243. package/dist/runtime/pool/index.d.ts.map +1 -0
  244. package/dist/runtime/pool/index.js +8 -0
  245. package/dist/runtime/pool/index.js.map +1 -0
  246. package/dist/runtime/pool/recycle.d.ts +44 -0
  247. package/dist/runtime/pool/recycle.d.ts.map +1 -0
  248. package/dist/runtime/pool/recycle.js +50 -0
  249. package/dist/runtime/pool/recycle.js.map +1 -0
  250. package/dist/runtime/pool/worker-pool.d.ts +77 -0
  251. package/dist/runtime/pool/worker-pool.d.ts.map +1 -0
  252. package/dist/runtime/pool/worker-pool.js +216 -0
  253. package/dist/runtime/pool/worker-pool.js.map +1 -0
  254. package/dist/runtime/pool/worker.d.ts +80 -0
  255. package/dist/runtime/pool/worker.d.ts.map +1 -0
  256. package/dist/runtime/pool/worker.js +324 -0
  257. package/dist/runtime/pool/worker.js.map +1 -0
  258. package/dist/server/mcp-server.d.ts +6 -0
  259. package/dist/server/mcp-server.d.ts.map +1 -1
  260. package/dist/server/mcp-server.js +610 -45
  261. package/dist/server/mcp-server.js.map +1 -1
  262. package/dist/server/passthrough-registrar.d.ts +73 -0
  263. package/dist/server/passthrough-registrar.d.ts.map +1 -0
  264. package/dist/server/passthrough-registrar.js +110 -0
  265. package/dist/server/passthrough-registrar.js.map +1 -0
  266. package/dist/skills/skills-engine.d.ts +9 -1
  267. package/dist/skills/skills-engine.d.ts.map +1 -1
  268. package/dist/skills/skills-engine.js +20 -3
  269. package/dist/skills/skills-engine.js.map +1 -1
  270. package/dist/utils/index.d.ts +3 -0
  271. package/dist/utils/index.d.ts.map +1 -1
  272. package/dist/utils/index.js +3 -0
  273. package/dist/utils/index.js.map +1 -1
  274. package/dist/utils/logger.d.ts.map +1 -1
  275. package/dist/utils/logger.js +5 -1
  276. package/dist/utils/logger.js.map +1 -1
  277. package/dist/utils/orphan-watch.d.ts +34 -0
  278. package/dist/utils/orphan-watch.d.ts.map +1 -0
  279. package/dist/utils/orphan-watch.js +54 -0
  280. package/dist/utils/orphan-watch.js.map +1 -0
  281. package/dist/utils/redact.d.ts +15 -0
  282. package/dist/utils/redact.d.ts.map +1 -0
  283. package/dist/utils/redact.js +48 -0
  284. package/dist/utils/redact.js.map +1 -0
  285. package/dist/utils/tokenize.d.ts +55 -0
  286. package/dist/utils/tokenize.d.ts.map +1 -0
  287. package/dist/utils/tokenize.js +205 -0
  288. package/dist/utils/tokenize.js.map +1 -0
  289. package/dist/version.d.ts +3 -3
  290. package/dist/version.d.ts.map +1 -1
  291. package/dist/version.js +3 -3
  292. package/dist/version.js.map +1 -1
  293. package/package.json +13 -3
@@ -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
+ * Bridge Session Registry
3
+ *
4
+ * Tracks `Mcp-Session-Id` values issued by the HTTP bridge. Sessions are
5
+ * generated on first request (or when a client presents an unknown id) and
6
+ * expire after a period of inactivity. Bounded to prevent unbounded growth
7
+ * if a misbehaving client rotates IDs.
8
+ *
9
+ * Per MCP spec 2025-03-26 Streamable HTTP transport:
10
+ * - session IDs MUST be globally unique and cryptographically secure
11
+ * - requests carrying a terminated / unknown id should return 404
12
+ * - servers MAY assign a new id on any request
13
+ */
14
+ interface SessionRecord {
15
+ id: string;
16
+ createdAt: number;
17
+ lastSeenAt: number;
18
+ }
19
+ export declare class SessionRegistry {
20
+ private readonly sessions;
21
+ private cleanupTimer;
22
+ private readonly ttlMs;
23
+ private readonly cleanupIntervalMs;
24
+ private readonly maxSessions;
25
+ constructor(opts?: {
26
+ ttlMs?: number;
27
+ cleanupIntervalMs?: number;
28
+ maxSessions?: number;
29
+ });
30
+ /**
31
+ * Begin periodic cleanup. Called by HttpBridge.start().
32
+ */
33
+ start(): void;
34
+ /**
35
+ * Stop the cleanup timer and drop all sessions. Called by HttpBridge.stop().
36
+ */
37
+ stop(): void;
38
+ /**
39
+ * Create a new session and return its id.
40
+ */
41
+ create(): string;
42
+ /**
43
+ * Look up a session. Returns undefined if the id is unknown or expired.
44
+ * Expired sessions are purged lazily here even if the sweep hasn't run yet.
45
+ */
46
+ touch(id: string): SessionRecord | undefined;
47
+ /**
48
+ * Explicit termination (e.g. DELETE /session).
49
+ * Returns true if a session was removed.
50
+ */
51
+ terminate(id: string): boolean;
52
+ size(): number;
53
+ /**
54
+ * Purge sessions older than ttlMs. Exposed for tests.
55
+ */
56
+ sweep(): number;
57
+ /**
58
+ * If we're at capacity, drop the oldest (by lastSeenAt) record to make room.
59
+ * Prevents unbounded growth under ID rotation.
60
+ */
61
+ private evictIfFull;
62
+ }
63
+ export {};
64
+ //# sourceMappingURL=session-registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-registry.d.ts","sourceRoot":"","sources":["../../src/bridge/session-registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAMH,UAAU,aAAa;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAoC;IAC7D,OAAO,CAAC,YAAY,CAA+B;IACnD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAS;IAC3C,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;gBAEzB,IAAI,CAAC,EAAE;QACjB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,iBAAiB,CAAC,EAAE,MAAM,CAAC;QAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB;IAOD;;OAEG;IACH,KAAK,IAAI,IAAI;IAQb;;OAEG;IACH,IAAI,IAAI,IAAI;IAQZ;;OAEG;IACH,MAAM,IAAI,MAAM;IAQhB;;;OAGG;IACH,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IAY5C;;;OAGG;IACH,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAI9B,IAAI,IAAI,MAAM;IAId;;OAEG;IACH,KAAK,IAAI,MAAM;IAef;;;OAGG;IACH,OAAO,CAAC,WAAW;CAepB"}
@@ -0,0 +1,124 @@
1
+ /**
2
+ * Bridge Session Registry
3
+ *
4
+ * Tracks `Mcp-Session-Id` values issued by the HTTP bridge. Sessions are
5
+ * generated on first request (or when a client presents an unknown id) and
6
+ * expire after a period of inactivity. Bounded to prevent unbounded growth
7
+ * if a misbehaving client rotates IDs.
8
+ *
9
+ * Per MCP spec 2025-03-26 Streamable HTTP transport:
10
+ * - session IDs MUST be globally unique and cryptographically secure
11
+ * - requests carrying a terminated / unknown id should return 404
12
+ * - servers MAY assign a new id on any request
13
+ */
14
+ import { randomUUID } from 'node:crypto';
15
+ import { logger } from '../utils/index.js';
16
+ import { LIFECYCLE_TIMEOUTS, MAX_BRIDGE_SESSIONS } from '../config/defaults.js';
17
+ export class SessionRegistry {
18
+ sessions = new Map();
19
+ cleanupTimer = null;
20
+ ttlMs;
21
+ cleanupIntervalMs;
22
+ maxSessions;
23
+ constructor(opts) {
24
+ this.ttlMs = opts?.ttlMs ?? LIFECYCLE_TIMEOUTS.BRIDGE_SESSION_TTL_MS;
25
+ this.cleanupIntervalMs =
26
+ opts?.cleanupIntervalMs ?? LIFECYCLE_TIMEOUTS.BRIDGE_SESSION_CLEANUP_INTERVAL_MS;
27
+ this.maxSessions = opts?.maxSessions ?? MAX_BRIDGE_SESSIONS;
28
+ }
29
+ /**
30
+ * Begin periodic cleanup. Called by HttpBridge.start().
31
+ */
32
+ start() {
33
+ if (this.cleanupTimer)
34
+ return;
35
+ this.cleanupTimer = setInterval(() => {
36
+ this.sweep();
37
+ }, this.cleanupIntervalMs);
38
+ this.cleanupTimer.unref?.();
39
+ }
40
+ /**
41
+ * Stop the cleanup timer and drop all sessions. Called by HttpBridge.stop().
42
+ */
43
+ stop() {
44
+ if (this.cleanupTimer) {
45
+ clearInterval(this.cleanupTimer);
46
+ this.cleanupTimer = null;
47
+ }
48
+ this.sessions.clear();
49
+ }
50
+ /**
51
+ * Create a new session and return its id.
52
+ */
53
+ create() {
54
+ this.evictIfFull();
55
+ const id = randomUUID();
56
+ const now = Date.now();
57
+ this.sessions.set(id, { id, createdAt: now, lastSeenAt: now });
58
+ return id;
59
+ }
60
+ /**
61
+ * Look up a session. Returns undefined if the id is unknown or expired.
62
+ * Expired sessions are purged lazily here even if the sweep hasn't run yet.
63
+ */
64
+ touch(id) {
65
+ const record = this.sessions.get(id);
66
+ if (!record)
67
+ return undefined;
68
+ const now = Date.now();
69
+ if (now - record.lastSeenAt > this.ttlMs) {
70
+ this.sessions.delete(id);
71
+ return undefined;
72
+ }
73
+ record.lastSeenAt = now;
74
+ return record;
75
+ }
76
+ /**
77
+ * Explicit termination (e.g. DELETE /session).
78
+ * Returns true if a session was removed.
79
+ */
80
+ terminate(id) {
81
+ return this.sessions.delete(id);
82
+ }
83
+ size() {
84
+ return this.sessions.size;
85
+ }
86
+ /**
87
+ * Purge sessions older than ttlMs. Exposed for tests.
88
+ */
89
+ sweep() {
90
+ const now = Date.now();
91
+ let removed = 0;
92
+ for (const [id, record] of this.sessions) {
93
+ if (now - record.lastSeenAt > this.ttlMs) {
94
+ this.sessions.delete(id);
95
+ removed++;
96
+ }
97
+ }
98
+ if (removed > 0) {
99
+ logger.debug('Bridge session sweep', { removed, remaining: this.sessions.size });
100
+ }
101
+ return removed;
102
+ }
103
+ /**
104
+ * If we're at capacity, drop the oldest (by lastSeenAt) record to make room.
105
+ * Prevents unbounded growth under ID rotation.
106
+ */
107
+ evictIfFull() {
108
+ if (this.sessions.size < this.maxSessions)
109
+ return;
110
+ let oldestId;
111
+ let oldestSeen = Number.POSITIVE_INFINITY;
112
+ for (const [id, record] of this.sessions) {
113
+ if (record.lastSeenAt < oldestSeen) {
114
+ oldestSeen = record.lastSeenAt;
115
+ oldestId = id;
116
+ }
117
+ }
118
+ if (oldestId) {
119
+ this.sessions.delete(oldestId);
120
+ logger.warn('Bridge session registry full, evicted oldest', { maxSessions: this.maxSessions });
121
+ }
122
+ }
123
+ }
124
+ //# sourceMappingURL=session-registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-registry.js","sourceRoot":"","sources":["../../src/bridge/session-registry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
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
+ constructor(options: CacheLayerOptions);
32
+ get(server: string, tool: string, args: unknown): Promise<ExtendedCacheHit | null>;
33
+ set(server: string, tool: string, args: unknown, result: unknown, options?: {
34
+ ttl?: number;
35
+ }): Promise<void>;
36
+ invalidate(server: string, pattern?: string): Promise<number>;
37
+ delta(server: string, tool: string, args: unknown, current: unknown): Promise<DeltaResult>;
38
+ stats(): CacheStats;
39
+ clear(): Promise<void>;
40
+ wouldCache(server: string, tool: string): boolean;
41
+ destroy(): void;
42
+ }
43
+ //# 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;gBAE/B,OAAO,EAAE,iBAAiB;IAgChC,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC;IAsDlF,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,OAAO,IAAI,IAAI;CAMhB"}