@iworkforces/tracelattice 2.0.7 → 2.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (217) hide show
  1. package/README.md +88 -64
  2. package/dist/ServerConfig.d.ts +1 -1
  3. package/dist/ServerConfig.js.map +1 -1
  4. package/dist/cli.js +223 -254
  5. package/dist/cli.js.map +1 -1
  6. package/dist/config/ConfigLoader.d.ts +29 -26
  7. package/dist/config/ConfigLoader.d.ts.map +1 -1
  8. package/dist/config/ConfigLoader.js +40 -36
  9. package/dist/config/ConfigLoader.js.map +1 -1
  10. package/dist/contracts/PersistenceBackend.d.ts +7 -108
  11. package/dist/contracts/PersistenceBackend.d.ts.map +1 -1
  12. package/dist/contracts/PersistenceBackend.js +1 -6
  13. package/dist/contracts/calibrator.d.ts +6 -6
  14. package/dist/contracts/calibrator.d.ts.map +1 -1
  15. package/dist/contracts/ids.d.ts +1 -8
  16. package/dist/contracts/ids.d.ts.map +1 -1
  17. package/dist/contracts/ids.js +2 -3
  18. package/dist/contracts/ids.js.map +1 -1
  19. package/dist/contracts/interfaces.d.ts +4 -6
  20. package/dist/contracts/interfaces.d.ts.map +1 -1
  21. package/dist/contracts/persistence-work.d.ts +2 -3
  22. package/dist/contracts/persistence-work.d.ts.map +1 -1
  23. package/dist/contracts/summary.d.ts +0 -1
  24. package/dist/contracts/summary.d.ts.map +1 -1
  25. package/dist/core/HistoryManager.d.ts +12 -16
  26. package/dist/core/HistoryManager.d.ts.map +1 -1
  27. package/dist/core/HistoryManager.js +19 -40
  28. package/dist/core/HistoryManager.js.map +1 -1
  29. package/dist/core/IHistoryManager.d.ts +22 -30
  30. package/dist/core/IHistoryManager.d.ts.map +1 -1
  31. package/dist/core/InputNormalizer.d.ts +7 -24
  32. package/dist/core/InputNormalizer.d.ts.map +1 -1
  33. package/dist/core/InputNormalizer.js +3 -9
  34. package/dist/core/InputNormalizer.js.map +1 -1
  35. package/dist/core/PersistenceBuffer.d.ts +3 -20
  36. package/dist/core/PersistenceBuffer.d.ts.map +1 -1
  37. package/dist/core/PersistenceBuffer.js +1 -4
  38. package/dist/core/PersistenceBuffer.js.map +1 -1
  39. package/dist/core/PersistenceRestore.d.ts +1 -1
  40. package/dist/core/PersistenceRestore.d.ts.map +1 -1
  41. package/dist/core/PersistenceRestore.js +4 -10
  42. package/dist/core/PersistenceRestore.js.map +1 -1
  43. package/dist/core/PersistenceWriter.d.ts.map +1 -1
  44. package/dist/core/PersistenceWriter.js +3 -12
  45. package/dist/core/PersistenceWriter.js.map +1 -1
  46. package/dist/core/SessionErrors.d.ts +0 -11
  47. package/dist/core/SessionErrors.d.ts.map +1 -1
  48. package/dist/core/SessionErrors.js +1 -14
  49. package/dist/core/SessionErrors.js.map +1 -1
  50. package/dist/core/SessionLock.d.ts +4 -5
  51. package/dist/core/SessionLock.d.ts.map +1 -1
  52. package/dist/core/SessionLock.js +5 -10
  53. package/dist/core/SessionLock.js.map +1 -1
  54. package/dist/core/SessionManager.d.ts +0 -2
  55. package/dist/core/SessionManager.d.ts.map +1 -1
  56. package/dist/core/SessionManager.js +3 -5
  57. package/dist/core/SessionManager.js.map +1 -1
  58. package/dist/core/SessionResetCoordinator.d.ts +10 -7
  59. package/dist/core/SessionResetCoordinator.d.ts.map +1 -1
  60. package/dist/core/SessionResetCoordinator.js +10 -28
  61. package/dist/core/SessionResetCoordinator.js.map +1 -1
  62. package/dist/core/ThoughtEvaluator.d.ts +5 -5
  63. package/dist/core/ThoughtEvaluator.d.ts.map +1 -1
  64. package/dist/core/ThoughtEvaluator.js +4 -40
  65. package/dist/core/ThoughtEvaluator.js.map +1 -1
  66. package/dist/core/ThoughtFormatter.js.map +1 -1
  67. package/dist/core/ThoughtProcessor.d.ts +10 -3
  68. package/dist/core/ThoughtProcessor.d.ts.map +1 -1
  69. package/dist/core/ThoughtProcessor.js +34 -38
  70. package/dist/core/ThoughtProcessor.js.map +1 -1
  71. package/dist/core/VerificationOutcomeAdmission.d.ts.map +1 -1
  72. package/dist/core/VerificationOutcomeAdmission.js +5 -7
  73. package/dist/core/VerificationOutcomeAdmission.js.map +1 -1
  74. package/dist/core/compression/CompressionService.d.ts +2 -1
  75. package/dist/core/compression/CompressionService.d.ts.map +1 -1
  76. package/dist/core/compression/CompressionService.js.map +1 -1
  77. package/dist/core/compression/DehydrationPolicy.d.ts.map +1 -1
  78. package/dist/core/compression/DehydrationPolicy.js.map +1 -1
  79. package/dist/core/compression/InMemorySummaryStore.d.ts +2 -1
  80. package/dist/core/compression/InMemorySummaryStore.d.ts.map +1 -1
  81. package/dist/core/compression/InMemorySummaryStore.js.map +1 -1
  82. package/dist/core/evaluator/Calibrator.d.ts +2 -2
  83. package/dist/core/evaluator/Calibrator.d.ts.map +1 -1
  84. package/dist/core/evaluator/Calibrator.js +2 -5
  85. package/dist/core/evaluator/Calibrator.js.map +1 -1
  86. package/dist/core/evaluator/SignalComputer.d.ts +2 -1
  87. package/dist/core/evaluator/SignalComputer.d.ts.map +1 -1
  88. package/dist/core/evaluator/SignalComputer.js.map +1 -1
  89. package/dist/core/evaluator/internals.d.ts +1 -5
  90. package/dist/core/evaluator/internals.d.ts.map +1 -1
  91. package/dist/core/evaluator/internals.js +1 -3
  92. package/dist/core/evaluator/internals.js.map +1 -1
  93. package/dist/core/graph/Edge.d.ts +1 -1
  94. package/dist/core/graph/EdgeEmitter.d.ts +2 -4
  95. package/dist/core/graph/EdgeEmitter.d.ts.map +1 -1
  96. package/dist/core/graph/EdgeEmitter.js +2 -4
  97. package/dist/core/graph/EdgeEmitter.js.map +1 -1
  98. package/dist/core/graph/GraphView.d.ts +13 -1
  99. package/dist/core/graph/GraphView.d.ts.map +1 -1
  100. package/dist/core/graph/GraphView.js +34 -0
  101. package/dist/core/graph/GraphView.js.map +1 -1
  102. package/dist/core/reasoning/OutcomeRecorder.d.ts +0 -1
  103. package/dist/core/reasoning/OutcomeRecorder.d.ts.map +1 -1
  104. package/dist/core/reasoning/OutcomeRecorder.js.map +1 -1
  105. package/dist/core/reasoning/strategies/SequentialStrategy.d.ts +3 -3
  106. package/dist/core/reasoning/strategies/SequentialStrategy.js.map +1 -1
  107. package/dist/core/reasoning/strategies/TreeOfThoughtStrategy.d.ts +6 -6
  108. package/dist/core/reasoning/strategies/TreeOfThoughtStrategy.d.ts.map +1 -1
  109. package/dist/core/reasoning/strategies/TreeOfThoughtStrategy.js +16 -2
  110. package/dist/core/reasoning/strategies/TreeOfThoughtStrategy.js.map +1 -1
  111. package/dist/core/reasoning/strategies/totScoring.d.ts.map +1 -1
  112. package/dist/core/reasoning/strategies/totScoring.js.map +1 -1
  113. package/dist/core/reasoning.d.ts +1 -3
  114. package/dist/core/reasoning.d.ts.map +1 -1
  115. package/dist/core/thought.d.ts +3 -2
  116. package/dist/core/thought.d.ts.map +1 -1
  117. package/dist/errors.d.ts +4 -20
  118. package/dist/errors.d.ts.map +1 -1
  119. package/dist/errors.js +2 -28
  120. package/dist/errors.js.map +1 -1
  121. package/dist/lib.d.ts +31 -24
  122. package/dist/lib.d.ts.map +1 -1
  123. package/dist/lib.js +55 -10
  124. package/dist/lib.js.map +1 -1
  125. package/dist/logger/NullLogger.d.ts +9 -11
  126. package/dist/logger/NullLogger.d.ts.map +1 -1
  127. package/dist/logger/NullLogger.js.map +1 -1
  128. package/dist/persistence/FilePersistence.d.ts +3 -12
  129. package/dist/persistence/FilePersistence.d.ts.map +1 -1
  130. package/dist/persistence/FilePersistence.js +9 -61
  131. package/dist/persistence/FilePersistence.js.map +1 -1
  132. package/dist/persistence/FileSnapshotV2.d.ts +2 -2
  133. package/dist/persistence/FileSnapshotV2.js +2 -2
  134. package/dist/persistence/FileSnapshotV2.js.map +1 -1
  135. package/dist/persistence/FileWriter.d.ts +1 -0
  136. package/dist/persistence/FileWriter.d.ts.map +1 -1
  137. package/dist/persistence/FileWriter.js +3 -3
  138. package/dist/persistence/FileWriter.js.map +1 -1
  139. package/dist/persistence/MemoryPersistence.d.ts +5 -15
  140. package/dist/persistence/MemoryPersistence.d.ts.map +1 -1
  141. package/dist/persistence/MemoryPersistence.js +6 -40
  142. package/dist/persistence/MemoryPersistence.js.map +1 -1
  143. package/dist/persistence/PersistenceCodec.js +1 -3
  144. package/dist/persistence/PersistenceCodec.js.map +1 -1
  145. package/dist/persistence/PersistenceErrors.d.ts +0 -6
  146. package/dist/persistence/PersistenceErrors.d.ts.map +1 -1
  147. package/dist/persistence/PersistenceErrors.js +1 -9
  148. package/dist/persistence/PersistenceErrors.js.map +1 -1
  149. package/dist/persistence/PersistenceScope.d.ts.map +1 -1
  150. package/dist/persistence/PersistenceScope.js +2 -2
  151. package/dist/persistence/PersistenceScope.js.map +1 -1
  152. package/dist/persistence/SqlitePersistence.d.ts +3 -10
  153. package/dist/persistence/SqlitePersistence.d.ts.map +1 -1
  154. package/dist/persistence/SqlitePersistence.js +2 -26
  155. package/dist/persistence/SqlitePersistence.js.map +1 -1
  156. package/dist/persistence/SqliteSchemaV2.d.ts.map +1 -1
  157. package/dist/persistence/SqliteSchemaV2.js +3 -12
  158. package/dist/persistence/SqliteSchemaV2.js.map +1 -1
  159. package/dist/pool/ConnectionPool.d.ts +3 -12
  160. package/dist/pool/ConnectionPool.d.ts.map +1 -1
  161. package/dist/pool/ConnectionPool.js +5 -8
  162. package/dist/pool/ConnectionPool.js.map +1 -1
  163. package/dist/pool/IConnectionPool.d.ts +3 -9
  164. package/dist/pool/IConnectionPool.d.ts.map +1 -1
  165. package/dist/registry/SkillRegistry.d.ts +1 -7
  166. package/dist/registry/SkillRegistry.d.ts.map +1 -1
  167. package/dist/registry/SkillRegistry.js +0 -15
  168. package/dist/registry/SkillRegistry.js.map +1 -1
  169. package/dist/registry/ToolRegistry.d.ts +1 -9
  170. package/dist/registry/ToolRegistry.d.ts.map +1 -1
  171. package/dist/registry/ToolRegistry.js +0 -21
  172. package/dist/registry/ToolRegistry.js.map +1 -1
  173. package/dist/schema.d.ts +2 -1
  174. package/dist/schema.d.ts.map +1 -1
  175. package/dist/schema.js +3 -3
  176. package/dist/schema.js.map +1 -1
  177. package/dist/transport/BaseTransport.d.ts +0 -9
  178. package/dist/transport/BaseTransport.d.ts.map +1 -1
  179. package/dist/transport/BaseTransport.js +0 -11
  180. package/dist/transport/BaseTransport.js.map +1 -1
  181. package/dist/transport/HttpHelpers.d.ts +4 -1
  182. package/dist/transport/HttpHelpers.d.ts.map +1 -1
  183. package/dist/transport/HttpHelpers.js +61 -11
  184. package/dist/transport/HttpHelpers.js.map +1 -1
  185. package/dist/transport/HttpRequestLifecycle.d.ts +15 -1
  186. package/dist/transport/HttpRequestLifecycle.d.ts.map +1 -1
  187. package/dist/transport/HttpRequestLifecycle.js +66 -4
  188. package/dist/transport/HttpRequestLifecycle.js.map +1 -1
  189. package/dist/transport/HttpTransport.d.ts +2 -0
  190. package/dist/transport/HttpTransport.d.ts.map +1 -1
  191. package/dist/transport/HttpTransport.js +75 -38
  192. package/dist/transport/HttpTransport.js.map +1 -1
  193. package/dist/transport/StreamableHttpTransport.d.ts +5 -29
  194. package/dist/transport/StreamableHttpTransport.d.ts.map +1 -1
  195. package/dist/transport/StreamableHttpTransport.js +74 -116
  196. package/dist/transport/StreamableHttpTransport.js.map +1 -1
  197. package/dist/watchers/SkillWatcher.d.ts.map +1 -1
  198. package/dist/watchers/SkillWatcher.js +1 -1
  199. package/dist/watchers/SkillWatcher.js.map +1 -1
  200. package/package.json +2 -2
  201. package/dist/contracts/PersistenceBackend.js.map +0 -1
  202. package/dist/persistence/FileLegacyImport.d.ts +0 -2
  203. package/dist/persistence/FileLegacyImport.d.ts.map +0 -1
  204. package/dist/persistence/FileLegacyImport.js +0 -183
  205. package/dist/persistence/FileLegacyImport.js.map +0 -1
  206. package/dist/persistence/SessionScopedPersistence.d.ts +0 -4
  207. package/dist/persistence/SessionScopedPersistence.d.ts.map +0 -1
  208. package/dist/persistence/SessionScopedPersistence.js +0 -9
  209. package/dist/persistence/SessionScopedPersistence.js.map +0 -1
  210. package/dist/persistence/SqliteLegacyImport.d.ts +0 -14
  211. package/dist/persistence/SqliteLegacyImport.d.ts.map +0 -1
  212. package/dist/persistence/SqliteLegacyImport.js +0 -136
  213. package/dist/persistence/SqliteLegacyImport.js.map +0 -1
  214. package/dist/persistence/SqliteLegacySchema.d.ts +0 -15
  215. package/dist/persistence/SqliteLegacySchema.d.ts.map +0 -1
  216. package/dist/persistence/SqliteLegacySchema.js +0 -72
  217. package/dist/persistence/SqliteLegacySchema.js.map +0 -1
@@ -1,3 +1,52 @@
1
+ class TrackedPreDispatchLease {
2
+ _onRelease;
3
+ _controller = new AbortController();
4
+ _settled = Promise.withResolvers();
5
+ _active = true;
6
+ _cancellationReason = null;
7
+ constructor(_onRelease){
8
+ this._onRelease = _onRelease;
9
+ }
10
+ get signal() {
11
+ return this._controller.signal;
12
+ }
13
+ get cancellationReason() {
14
+ return this._cancellationReason;
15
+ }
16
+ get settled() {
17
+ return this._settled.promise;
18
+ }
19
+ cancel(reason) {
20
+ if (!this._active || this._controller.signal.aborted) return;
21
+ this._cancellationReason = reason;
22
+ this._controller.abort();
23
+ }
24
+ release() {
25
+ if (!this._active) return;
26
+ this._active = false;
27
+ this._onRelease(this);
28
+ this._settled.resolve();
29
+ }
30
+ }
31
+ class PreDispatchTracker {
32
+ _leases = new Set();
33
+ _accepting = true;
34
+ acquire() {
35
+ if (!this._accepting) return null;
36
+ const lease = new TrackedPreDispatchLease((released)=>this._leases.delete(released));
37
+ this._leases.add(lease);
38
+ return lease;
39
+ }
40
+ closeAdmission(reason) {
41
+ this._accepting = false;
42
+ for (const lease of this._leases)lease.cancel(reason);
43
+ }
44
+ async join() {
45
+ while(this._leases.size > 0)await Promise.all([
46
+ ...this._leases
47
+ ].map((lease)=>lease.settled));
48
+ }
49
+ }
1
50
  const LIFECYCLE_REPORTING_FAILURE_CAPACITY = 32;
2
51
  class LifecycleFailureReporter {
3
52
  _onFailure;
@@ -69,19 +118,32 @@ class AcceptedWorkTracker {
69
118
  get size() {
70
119
  return this._work.size;
71
120
  }
72
- track(work) {
121
+ transfer(lease, start) {
122
+ lease.signal.throwIfAborted();
123
+ const reservation = Promise.withResolvers();
124
+ this._work.add(reservation.promise);
125
+ lease.release();
126
+ let work;
127
+ try {
128
+ work = start();
129
+ } catch (error) {
130
+ this._work.delete(reservation.promise);
131
+ reservation.resolve();
132
+ throw error;
133
+ }
73
134
  const observed = work.catch((error)=>{
74
135
  this._failureReporter.report(error);
75
136
  });
76
- this._work.add(observed);
77
137
  observed.then(()=>{
78
- this._work.delete(observed);
138
+ this._work.delete(reservation.promise);
139
+ reservation.resolve();
79
140
  });
141
+ return work;
80
142
  }
81
143
  async join() {
82
144
  while(this._work.size > 0)await Promise.all(this._work);
83
145
  }
84
146
  }
85
- export { AcceptedWorkTracker, LIFECYCLE_REPORTING_FAILURE_CAPACITY, LifecycleFailureReporter, ResponseFinalizer };
147
+ export { AcceptedWorkTracker, LIFECYCLE_REPORTING_FAILURE_CAPACITY, LifecycleFailureReporter, PreDispatchTracker, ResponseFinalizer };
86
148
 
87
149
  //# sourceMappingURL=HttpRequestLifecycle.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"transport/HttpRequestLifecycle.js","sources":["../../src/transport/HttpRequestLifecycle.ts"],"sourcesContent":["import type { ServerResponse } from 'node:http';\n\ntype ResponseWriter = (response: ServerResponse) => void;\ntype WorkFailureHandler = (error: unknown) => void;\n\nexport type LifecycleReportingFailure = {\n\treadonly lifecycleError: unknown;\n\treadonly reportingError: unknown;\n};\n\n/** Maximum number of reporting failures retained for diagnostics. */\nexport const LIFECYCLE_REPORTING_FAILURE_CAPACITY = 32;\n\nexport class LifecycleFailureReporter {\n\tprivate readonly _reportingFailures: LifecycleReportingFailure[] = [];\n\tprivate _reportingFailureCount = 0;\n\tprivate _droppedReportingFailureCount = 0;\n\n\tconstructor(private readonly _onFailure: WorkFailureHandler) {}\n\n\tget reportingFailures(): readonly LifecycleReportingFailure[] {\n\t\treturn [...this._reportingFailures];\n\t}\n\n\tget reportingFailureCount(): number {\n\t\treturn this._reportingFailureCount;\n\t}\n\n\tget droppedReportingFailureCount(): number {\n\t\treturn this._droppedReportingFailureCount;\n\t}\n\n\treport(error: unknown): void {\n\t\ttry {\n\t\t\tthis._onFailure(error);\n\t\t} catch (reportingError) {\n\t\t\tthis._reportingFailureCount++;\n\t\t\tif (this._reportingFailures.length === LIFECYCLE_REPORTING_FAILURE_CAPACITY) {\n\t\t\t\tthis._reportingFailures.shift();\n\t\t\t\tthis._droppedReportingFailureCount++;\n\t\t\t}\n\t\t\tthis._reportingFailures.push({ lifecycleError: error, reportingError });\n\t\t}\n\t}\n}\n\nexport class ResponseFinalizer {\n\tprivate _isFinalized = false;\n\n\tconstructor(\n\t\tprivate readonly _response: ServerResponse,\n\t\tprivate readonly _failureReporter: LifecycleFailureReporter\n\t) {\n\t\tthis._response.once('close', () => {\n\t\t\tthis._isFinalized = true;\n\t\t});\n\t}\n\n\tfinalize(writer: ResponseWriter): boolean {\n\t\tif (this._isFinalized || this._response.destroyed || this._response.writableEnded) {\n\t\t\tthis._isFinalized = true;\n\t\t\treturn false;\n\t\t}\n\n\t\tthis._isFinalized = true;\n\t\ttry {\n\t\t\twriter(this._response);\n\t\t} catch (error) {\n\t\t\tthis._failureReporter.report(error);\n\t\t\tthis._response.destroy();\n\t\t}\n\t\treturn true;\n\t}\n}\n\nexport class AcceptedWorkTracker {\n\tprivate readonly _work = new Set<Promise<void>>();\n\n\tconstructor(private readonly _failureReporter: LifecycleFailureReporter) {}\n\n\tget size(): number {\n\t\treturn this._work.size;\n\t}\n\n\ttrack(work: Promise<void>): void {\n\t\tconst observed = work.catch((error: unknown) => {\n\t\t\tthis._failureReporter.report(error);\n\t\t});\n\t\tthis._work.add(observed);\n\t\tvoid observed.then(() => {\n\t\t\tthis._work.delete(observed);\n\t\t});\n\t}\n\n\tasync join(): Promise<void> {\n\t\twhile (this._work.size > 0) {\n\t\t\tawait Promise.all(this._work);\n\t\t}\n\t}\n}\n"],"names":["LIFECYCLE_REPORTING_FAILURE_CAPACITY","LifecycleFailureReporter","_onFailure","error","reportingError","ResponseFinalizer","_response","_failureReporter","writer","AcceptedWorkTracker","Set","work","observed","Promise"],"mappings":"AAWO,MAAMA,uCAAuC;AAE7C,MAAMC;;IACK,qBAAkD,EAAE,CAAC;IAC9D,yBAAyB,EAAE;IAC3B,gCAAgC,EAAE;IAE1C,YAA6BC,UAA8B,CAAE;aAAhCA,UAAU,GAAVA;IAAiC;IAE9D,IAAI,oBAA0D;QAC7D,OAAO;eAAI,IAAI,CAAC,kBAAkB;SAAC;IACpC;IAEA,IAAI,wBAAgC;QACnC,OAAO,IAAI,CAAC,sBAAsB;IACnC;IAEA,IAAI,+BAAuC;QAC1C,OAAO,IAAI,CAAC,6BAA6B;IAC1C;IAEA,OAAOC,KAAc,EAAQ;QAC5B,IAAI;YACH,IAAI,CAAC,UAAU,CAACA;QACjB,EAAE,OAAOC,gBAAgB;YACxB,IAAI,CAAC,sBAAsB;YAC3B,IAAI,IAAI,CAAC,kBAAkB,CAAC,MAAM,KAAKJ,sCAAsC;gBAC5E,IAAI,CAAC,kBAAkB,CAAC,KAAK;gBAC7B,IAAI,CAAC,6BAA6B;YACnC;YACA,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC;gBAAE,gBAAgBG;gBAAOC;YAAe;QACtE;IACD;AACD;AAEO,MAAMC;;;IACJ,eAAe,MAAM;IAE7B,YACkBC,SAAyB,EACzBC,gBAA0C,CAC1D;aAFgBD,SAAS,GAATA;aACAC,gBAAgB,GAAhBA;QAEjB,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,SAAS;YAC5B,IAAI,CAAC,YAAY,GAAG;QACrB;IACD;IAEA,SAASC,MAAsB,EAAW;QACzC,IAAI,IAAI,CAAC,YAAY,IAAI,IAAI,CAAC,SAAS,CAAC,SAAS,IAAI,IAAI,CAAC,SAAS,CAAC,aAAa,EAAE;YAClF,IAAI,CAAC,YAAY,GAAG;YACpB,OAAO;QACR;QAEA,IAAI,CAAC,YAAY,GAAG;QACpB,IAAI;YACHA,OAAO,IAAI,CAAC,SAAS;QACtB,EAAE,OAAOL,OAAO;YACf,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAACA;YAC7B,IAAI,CAAC,SAAS,CAAC,OAAO;QACvB;QACA,OAAO;IACR;AACD;AAEO,MAAMM;;IACK,QAAQ,IAAIC,MAAqB;IAElD,YAA6BH,gBAA0C,CAAE;aAA5CA,gBAAgB,GAAhBA;IAA6C;IAE1E,IAAI,OAAe;QAClB,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI;IACvB;IAEA,MAAMI,IAAmB,EAAQ;QAChC,MAAMC,WAAWD,KAAK,KAAK,CAAC,CAACR;YAC5B,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAACA;QAC9B;QACA,IAAI,CAAC,KAAK,CAAC,GAAG,CAACS;QACVA,SAAS,IAAI,CAAC;YAClB,IAAI,CAAC,KAAK,CAAC,MAAM,CAACA;QACnB;IACD;IAEA,MAAM,OAAsB;QAC3B,MAAO,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,EACxB,MAAMC,QAAQ,GAAG,CAAC,IAAI,CAAC,KAAK;IAE9B;AACD"}
1
+ {"version":3,"file":"transport/HttpRequestLifecycle.js","sources":["../../src/transport/HttpRequestLifecycle.ts"],"sourcesContent":["import type { ServerResponse } from 'node:http';\n\ntype ResponseWriter = (response: ServerResponse) => void;\ntype WorkFailureHandler = (error: unknown) => void;\n\nexport type PreDispatchCancellationReason = 'peer' | 'shutdown' | 'timeout';\n\nexport interface PreDispatchLease {\n\treadonly signal: AbortSignal;\n\treadonly cancellationReason: PreDispatchCancellationReason | null;\n\tcancel(reason: PreDispatchCancellationReason): void;\n\trelease(): void;\n}\n\nclass TrackedPreDispatchLease implements PreDispatchLease {\n\tprivate readonly _controller = new AbortController();\n\tprivate readonly _settled = Promise.withResolvers<void>();\n\tprivate _active = true;\n\tprivate _cancellationReason: PreDispatchCancellationReason | null = null;\n\n\tconstructor(private readonly _onRelease: (lease: TrackedPreDispatchLease) => void) {}\n\n\tget signal(): AbortSignal {\n\t\treturn this._controller.signal;\n\t}\n\n\tget cancellationReason(): PreDispatchCancellationReason | null {\n\t\treturn this._cancellationReason;\n\t}\n\n\tget settled(): Promise<void> {\n\t\treturn this._settled.promise;\n\t}\n\n\tcancel(reason: PreDispatchCancellationReason): void {\n\t\tif (!this._active || this._controller.signal.aborted) return;\n\t\tthis._cancellationReason = reason;\n\t\tthis._controller.abort();\n\t}\n\n\trelease(): void {\n\t\tif (!this._active) return;\n\t\tthis._active = false;\n\t\tthis._onRelease(this);\n\t\tthis._settled.resolve();\n\t}\n}\n\nexport class PreDispatchTracker {\n\tprivate readonly _leases = new Set<TrackedPreDispatchLease>();\n\tprivate _accepting = true;\n\n\tacquire(): PreDispatchLease | null {\n\t\tif (!this._accepting) return null;\n\t\tconst lease = new TrackedPreDispatchLease((released) => this._leases.delete(released));\n\t\tthis._leases.add(lease);\n\t\treturn lease;\n\t}\n\n\tcloseAdmission(reason: PreDispatchCancellationReason): void {\n\t\tthis._accepting = false;\n\t\tfor (const lease of this._leases) lease.cancel(reason);\n\t}\n\n\tasync join(): Promise<void> {\n\t\twhile (this._leases.size > 0) {\n\t\t\tawait Promise.all([...this._leases].map((lease) => lease.settled));\n\t\t}\n\t}\n}\n\nexport type LifecycleReportingFailure = {\n\treadonly lifecycleError: unknown;\n\treadonly reportingError: unknown;\n};\n\n/** Maximum number of reporting failures retained for diagnostics. */\nexport const LIFECYCLE_REPORTING_FAILURE_CAPACITY = 32;\n\nexport class LifecycleFailureReporter {\n\tprivate readonly _reportingFailures: LifecycleReportingFailure[] = [];\n\tprivate _reportingFailureCount = 0;\n\tprivate _droppedReportingFailureCount = 0;\n\n\tconstructor(private readonly _onFailure: WorkFailureHandler) {}\n\n\tget reportingFailures(): readonly LifecycleReportingFailure[] {\n\t\treturn [...this._reportingFailures];\n\t}\n\n\tget reportingFailureCount(): number {\n\t\treturn this._reportingFailureCount;\n\t}\n\n\tget droppedReportingFailureCount(): number {\n\t\treturn this._droppedReportingFailureCount;\n\t}\n\n\treport(error: unknown): void {\n\t\ttry {\n\t\t\tthis._onFailure(error);\n\t\t} catch (reportingError) {\n\t\t\tthis._reportingFailureCount++;\n\t\t\tif (this._reportingFailures.length === LIFECYCLE_REPORTING_FAILURE_CAPACITY) {\n\t\t\t\tthis._reportingFailures.shift();\n\t\t\t\tthis._droppedReportingFailureCount++;\n\t\t\t}\n\t\t\tthis._reportingFailures.push({ lifecycleError: error, reportingError });\n\t\t}\n\t}\n}\n\nexport class ResponseFinalizer {\n\tprivate _isFinalized = false;\n\n\tconstructor(\n\t\tprivate readonly _response: ServerResponse,\n\t\tprivate readonly _failureReporter: LifecycleFailureReporter\n\t) {\n\t\tthis._response.once('close', () => {\n\t\t\tthis._isFinalized = true;\n\t\t});\n\t}\n\n\tfinalize(writer: ResponseWriter): boolean {\n\t\tif (this._isFinalized || this._response.destroyed || this._response.writableEnded) {\n\t\t\tthis._isFinalized = true;\n\t\t\treturn false;\n\t\t}\n\n\t\tthis._isFinalized = true;\n\t\ttry {\n\t\t\twriter(this._response);\n\t\t} catch (error) {\n\t\t\tthis._failureReporter.report(error);\n\t\t\tthis._response.destroy();\n\t\t}\n\t\treturn true;\n\t}\n}\n\nexport class AcceptedWorkTracker {\n\tprivate readonly _work = new Set<Promise<void>>();\n\n\tconstructor(private readonly _failureReporter: LifecycleFailureReporter) {}\n\n\tget size(): number {\n\t\treturn this._work.size;\n\t}\n\n\ttransfer(lease: PreDispatchLease, start: () => Promise<void>): Promise<void> {\n\t\tlease.signal.throwIfAborted();\n\t\tconst reservation = Promise.withResolvers<void>();\n\t\tthis._work.add(reservation.promise);\n\t\tlease.release();\n\n\t\tlet work: Promise<void>;\n\t\ttry {\n\t\t\twork = start();\n\t\t} catch (error) {\n\t\t\tthis._work.delete(reservation.promise);\n\t\t\treservation.resolve();\n\t\t\tthrow error;\n\t\t}\n\n\t\tconst observed = work.catch((error: unknown) => {\n\t\t\tthis._failureReporter.report(error);\n\t\t});\n\t\tvoid observed.then(() => {\n\t\t\tthis._work.delete(reservation.promise);\n\t\t\treservation.resolve();\n\t\t});\n\t\treturn work;\n\t}\n\n\tasync join(): Promise<void> {\n\t\twhile (this._work.size > 0) {\n\t\t\tawait Promise.all(this._work);\n\t\t}\n\t}\n}\n"],"names":["TrackedPreDispatchLease","AbortController","Promise","_onRelease","reason","PreDispatchTracker","Set","lease","released","LIFECYCLE_REPORTING_FAILURE_CAPACITY","LifecycleFailureReporter","_onFailure","error","reportingError","ResponseFinalizer","_response","_failureReporter","writer","AcceptedWorkTracker","start","reservation","work","observed"],"mappings":"AAcA,MAAMA;;IACY,cAAc,IAAIC,kBAAkB;IACpC,WAAWC,QAAQ,aAAa,GAAS;IAClD,UAAU,KAAK;IACf,sBAA4D,KAAK;IAEzE,YAA6BC,UAAoD,CAAE;aAAtDA,UAAU,GAAVA;IAAuD;IAEpF,IAAI,SAAsB;QACzB,OAAO,IAAI,CAAC,WAAW,CAAC,MAAM;IAC/B;IAEA,IAAI,qBAA2D;QAC9D,OAAO,IAAI,CAAC,mBAAmB;IAChC;IAEA,IAAI,UAAyB;QAC5B,OAAO,IAAI,CAAC,QAAQ,CAAC,OAAO;IAC7B;IAEA,OAAOC,MAAqC,EAAQ;QACnD,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,EAAE;QACtD,IAAI,CAAC,mBAAmB,GAAGA;QAC3B,IAAI,CAAC,WAAW,CAAC,KAAK;IACvB;IAEA,UAAgB;QACf,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE;QACnB,IAAI,CAAC,OAAO,GAAG;QACf,IAAI,CAAC,UAAU,CAAC,IAAI;QACpB,IAAI,CAAC,QAAQ,CAAC,OAAO;IACtB;AACD;AAEO,MAAMC;IACK,UAAU,IAAIC,MAA+B;IACtD,aAAa,KAAK;IAE1B,UAAmC;QAClC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,OAAO;QAC7B,MAAMC,QAAQ,IAAIP,wBAAwB,CAACQ,WAAa,IAAI,CAAC,OAAO,CAAC,MAAM,CAACA;QAC5E,IAAI,CAAC,OAAO,CAAC,GAAG,CAACD;QACjB,OAAOA;IACR;IAEA,eAAeH,MAAqC,EAAQ;QAC3D,IAAI,CAAC,UAAU,GAAG;QAClB,KAAK,MAAMG,SAAS,IAAI,CAAC,OAAO,CAAEA,MAAM,MAAM,CAACH;IAChD;IAEA,MAAM,OAAsB;QAC3B,MAAO,IAAI,CAAC,OAAO,CAAC,IAAI,GAAG,EAC1B,MAAMF,QAAQ,GAAG,CAAC;eAAI,IAAI,CAAC,OAAO;SAAC,CAAC,GAAG,CAAC,CAACK,QAAUA,MAAM,OAAO;IAElE;AACD;AAQO,MAAME,uCAAuC;AAE7C,MAAMC;;IACK,qBAAkD,EAAE,CAAC;IAC9D,yBAAyB,EAAE;IAC3B,gCAAgC,EAAE;IAE1C,YAA6BC,UAA8B,CAAE;aAAhCA,UAAU,GAAVA;IAAiC;IAE9D,IAAI,oBAA0D;QAC7D,OAAO;eAAI,IAAI,CAAC,kBAAkB;SAAC;IACpC;IAEA,IAAI,wBAAgC;QACnC,OAAO,IAAI,CAAC,sBAAsB;IACnC;IAEA,IAAI,+BAAuC;QAC1C,OAAO,IAAI,CAAC,6BAA6B;IAC1C;IAEA,OAAOC,KAAc,EAAQ;QAC5B,IAAI;YACH,IAAI,CAAC,UAAU,CAACA;QACjB,EAAE,OAAOC,gBAAgB;YACxB,IAAI,CAAC,sBAAsB;YAC3B,IAAI,IAAI,CAAC,kBAAkB,CAAC,MAAM,KAAKJ,sCAAsC;gBAC5E,IAAI,CAAC,kBAAkB,CAAC,KAAK;gBAC7B,IAAI,CAAC,6BAA6B;YACnC;YACA,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC;gBAAE,gBAAgBG;gBAAOC;YAAe;QACtE;IACD;AACD;AAEO,MAAMC;;;IACJ,eAAe,MAAM;IAE7B,YACkBC,SAAyB,EACzBC,gBAA0C,CAC1D;aAFgBD,SAAS,GAATA;aACAC,gBAAgB,GAAhBA;QAEjB,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,SAAS;YAC5B,IAAI,CAAC,YAAY,GAAG;QACrB;IACD;IAEA,SAASC,MAAsB,EAAW;QACzC,IAAI,IAAI,CAAC,YAAY,IAAI,IAAI,CAAC,SAAS,CAAC,SAAS,IAAI,IAAI,CAAC,SAAS,CAAC,aAAa,EAAE;YAClF,IAAI,CAAC,YAAY,GAAG;YACpB,OAAO;QACR;QAEA,IAAI,CAAC,YAAY,GAAG;QACpB,IAAI;YACHA,OAAO,IAAI,CAAC,SAAS;QACtB,EAAE,OAAOL,OAAO;YACf,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAACA;YAC7B,IAAI,CAAC,SAAS,CAAC,OAAO;QACvB;QACA,OAAO;IACR;AACD;AAEO,MAAMM;;IACK,QAAQ,IAAIZ,MAAqB;IAElD,YAA6BU,gBAA0C,CAAE;aAA5CA,gBAAgB,GAAhBA;IAA6C;IAE1E,IAAI,OAAe;QAClB,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI;IACvB;IAEA,SAAST,KAAuB,EAAEY,KAA0B,EAAiB;QAC5EZ,MAAM,MAAM,CAAC,cAAc;QAC3B,MAAMa,cAAclB,QAAQ,aAAa;QACzC,IAAI,CAAC,KAAK,CAAC,GAAG,CAACkB,YAAY,OAAO;QAClCb,MAAM,OAAO;QAEb,IAAIc;QACJ,IAAI;YACHA,OAAOF;QACR,EAAE,OAAOP,OAAO;YACf,IAAI,CAAC,KAAK,CAAC,MAAM,CAACQ,YAAY,OAAO;YACrCA,YAAY,OAAO;YACnB,MAAMR;QACP;QAEA,MAAMU,WAAWD,KAAK,KAAK,CAAC,CAACT;YAC5B,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAACA;QAC9B;QACKU,SAAS,IAAI,CAAC;YAClB,IAAI,CAAC,KAAK,CAAC,MAAM,CAACF,YAAY,OAAO;YACrCA,YAAY,OAAO;QACpB;QACA,OAAOC;IACR;IAEA,MAAM,OAAsB;QAC3B,MAAO,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,EACxB,MAAMnB,QAAQ,GAAG,CAAC,IAAI,CAAC,KAAK;IAE9B;AACD"}
@@ -86,6 +86,7 @@ export declare class HttpTransport extends BaseTransport implements ITransport {
86
86
  private _metricsProvider;
87
87
  private readonly _lifecycleFailureReporter;
88
88
  private readonly _acceptedWork;
89
+ private readonly _preDispatch;
89
90
  private _stopPromise;
90
91
  constructor(options?: HttpTransportOptions);
91
92
  private _requireMcpServer;
@@ -101,6 +102,7 @@ export declare class HttpTransport extends BaseTransport implements ITransport {
101
102
  * Track an error in metrics.
102
103
  */
103
104
  private _trackError;
105
+ private _parseJsonRpcRequest;
104
106
  /**
105
107
  * Route and handle incoming HTTP requests.
106
108
  *
@@ -1 +1 @@
1
- {"version":3,"file":"HttpTransport.d.ts","sourceRoot":"","sources":["../../src/transport/HttpTransport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAKH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AAEtC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AAG3D,OAAO,EAAE,aAAa,EAAE,KAAK,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC1E,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAc3E,MAAM,WAAW,oBAAqB,SAAQ,gBAAgB;IAC7D;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,QAAQ,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,MAAM,CAAC;IAE/B;;;OAGG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAE9B;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,qBAAa,aAAc,SAAQ,aAAc,YAAW,UAAU;IACrE,IAAI,IAAI,IAAI,aAAa,CAExB;IACD,OAAO,CAAC,OAAO,CAAkC;IACjD,OAAO,CAAC,UAAU,CAA0B;IAC5C,OAAO,CAAC,eAAe,CAAS;IAChC,OAAO,CAAC,qBAAqB,CAAU;IACvC,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,aAAa,CAAa;IAClC,OAAO,CAAC,eAAe,CAAa;IACpC,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,QAAQ,CAAC,CAAW;IAC5B,OAAO,CAAC,gBAAgB,CAAwB;IAChD,OAAO,CAAC,QAAQ,CAAC,yBAAyB,CAA2B;IACrE,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAsB;IACpD,OAAO,CAAC,YAAY,CAA8B;gBAEtC,OAAO,GAAE,oBAAyB;IAwB9C,OAAO,CAAC,iBAAiB;IAOzB;;OAEG;IACH,IAAI,WAAW,IAAI,MAAM,CAExB;IAED;;OAEG;IACG,OAAO,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IA4BlD;;OAEG;IACH,OAAO,CAAC,WAAW;IASnB;;;;;OAKG;YACW,cAAc;IAoE5B;;;;;OAKG;YACW,kBAAkB;IA0FhC;;OAEG;IACH,IAAI,YAAY,IAAI,MAAM,CAEzB;IAED;;OAEG;IACH,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CA0BrB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,GAAE,oBAAyB,GAAG,aAAa,CAErF"}
1
+ {"version":3,"file":"HttpTransport.d.ts","sourceRoot":"","sources":["../../src/transport/HttpTransport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAKH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AAEtC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AAG3D,OAAO,EAAE,aAAa,EAAE,KAAK,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC1E,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAgB3E,MAAM,WAAW,oBAAqB,SAAQ,gBAAgB;IAC7D;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,QAAQ,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,MAAM,CAAC;IAE/B;;;OAGG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAE9B;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,qBAAa,aAAc,SAAQ,aAAc,YAAW,UAAU;IACrE,IAAI,IAAI,IAAI,aAAa,CAExB;IACD,OAAO,CAAC,OAAO,CAAkC;IACjD,OAAO,CAAC,UAAU,CAA0B;IAC5C,OAAO,CAAC,eAAe,CAAS;IAChC,OAAO,CAAC,qBAAqB,CAAU;IACvC,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,aAAa,CAAa;IAClC,OAAO,CAAC,eAAe,CAAa;IACpC,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,QAAQ,CAAC,CAAW;IAC5B,OAAO,CAAC,gBAAgB,CAAwB;IAChD,OAAO,CAAC,QAAQ,CAAC,yBAAyB,CAA2B;IACrE,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAsB;IACpD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAA4B;IACzD,OAAO,CAAC,YAAY,CAA8B;gBAEtC,OAAO,GAAE,oBAAyB;IAwB9C,OAAO,CAAC,iBAAiB;IAOzB;;OAEG;IACH,IAAI,WAAW,IAAI,MAAM,CAExB;IAED;;OAEG;IACG,OAAO,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IA4BlD;;OAEG;IACH,OAAO,CAAC,WAAW;IASnB,OAAO,CAAC,oBAAoB;IAqC5B;;;;;OAKG;YACW,cAAc;IA4E5B;;;;;OAKG;YACW,kBAAkB;IAiGhC;;OAEG;IACH,IAAI,YAAY,IAAI,MAAM,CAEzB;IAED;;OAEG;IACH,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CA8BrB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,GAAE,oBAAyB,GAAG,aAAa,CAErF"}
@@ -6,7 +6,7 @@ import { JsonRpcRequestSchema } from "../schema.js";
6
6
  import { BaseTransport } from "./BaseTransport.js";
7
7
  import { readRequestBody, sendCorsPreflight, sendJsonRpcError, sendJsonRpcResponse } from "./HttpHelpers.js";
8
8
  import { runWithContext } from "../context/RequestContext.js";
9
- import { AcceptedWorkTracker, LifecycleFailureReporter, ResponseFinalizer } from "./HttpRequestLifecycle.js";
9
+ import { AcceptedWorkTracker, LifecycleFailureReporter, PreDispatchTracker, ResponseFinalizer } from "./HttpRequestLifecycle.js";
10
10
  class HttpTransport extends BaseTransport {
11
11
  get kind() {
12
12
  return 'http';
@@ -23,6 +23,7 @@ class HttpTransport extends BaseTransport {
23
23
  _metricsProvider;
24
24
  _lifecycleFailureReporter;
25
25
  _acceptedWork;
26
+ _preDispatch = new PreDispatchTracker();
26
27
  _stopPromise = null;
27
28
  constructor(options = {}){
28
29
  super(options);
@@ -88,6 +89,28 @@ class HttpTransport extends BaseTransport {
88
89
  error_type: errorType
89
90
  }, 'Total HTTP request errors');
90
91
  }
92
+ _parseJsonRpcRequest(body, responseFinalizer) {
93
+ let rawBody;
94
+ try {
95
+ rawBody = JSON.parse(body);
96
+ } catch {
97
+ this._trackError('parse_error');
98
+ responseFinalizer.finalize((response)=>{
99
+ sendJsonRpcError(response, 200, -32700, 'Parse error');
100
+ });
101
+ return null;
102
+ }
103
+ const parseResult = safeParse(JsonRpcRequestSchema, rawBody);
104
+ const rawId = rawBody && 'object' == typeof rawBody && 'id' in rawBody ? rawBody.id ?? null : null;
105
+ if (!parseResult.success) {
106
+ this._trackError('validation');
107
+ responseFinalizer.finalize((response)=>{
108
+ sendJsonRpcError(response, 200, -32600, 'Invalid Request', rawId, parseResult.issues);
109
+ });
110
+ return null;
111
+ }
112
+ return parseResult.output;
113
+ }
91
114
  async _handleRequest(req, res) {
92
115
  const startTime = Date.now();
93
116
  const requestPath = req.url || '/';
@@ -135,23 +158,37 @@ class HttpTransport extends BaseTransport {
135
158
  requests: this._requestCount
136
159
  });
137
160
  if ('GET' === req.method && '/ready' === req.url) return this.handleReadinessEndpoint(res);
138
- if ('POST' === req.method && req.url === this._path) return void this._acceptedWork.track(this._handlePostRequest(req, res));
161
+ if ('POST' === req.method && req.url === this._path) {
162
+ const lease = this._preDispatch.acquire();
163
+ if (!lease) {
164
+ const responseFinalizer = new ResponseFinalizer(res, this._lifecycleFailureReporter);
165
+ responseFinalizer.finalize((response)=>{
166
+ sendJsonRpcError(response, 503, -32603, 'Server is shutting down');
167
+ });
168
+ return;
169
+ }
170
+ await this._handlePostRequest(req, res, lease);
171
+ return;
172
+ }
139
173
  this._trackError('not_found');
140
174
  sendJsonRpcError(res, 404, -32601, 'Not Found');
141
175
  }
142
- async _handlePostRequest(req, res) {
176
+ async _handlePostRequest(req, res, lease) {
143
177
  this._requestCount++;
144
178
  this._activeRequests++;
145
179
  const responseFinalizer = new ResponseFinalizer(res, this._lifecycleFailureReporter);
180
+ const onAborted = ()=>lease.cancel('peer');
181
+ req.once('aborted', onAborted);
146
182
  const timeout = setTimeout(()=>{
147
183
  this._trackError('timeout');
148
184
  responseFinalizer.finalize((response)=>{
149
185
  sendJsonRpcError(response, 500, -32603, 'Request timeout');
150
186
  });
187
+ lease.cancel('timeout');
151
188
  }, this._requestTimeout);
152
189
  try {
153
190
  const maxBodySize = this._bodySizeLimitEnabled ? this._maxBodySize : 0;
154
- const body = await readRequestBody(req, maxBodySize);
191
+ const body = await readRequestBody(req, maxBodySize, lease.signal);
155
192
  if (null === body) {
156
193
  this._trackError('payload_too_large');
157
194
  responseFinalizer.finalize((response)=>{
@@ -159,53 +196,52 @@ class HttpTransport extends BaseTransport {
159
196
  });
160
197
  return;
161
198
  }
162
- let rawBody;
163
- try {
164
- rawBody = JSON.parse(body);
165
- } catch {
166
- this._trackError('parse_error');
167
- responseFinalizer.finalize((response)=>{
168
- sendJsonRpcError(response, 200, -32700, 'Parse error');
169
- });
170
- return;
171
- }
172
- const parseResult = safeParse(JsonRpcRequestSchema, rawBody);
173
- const rawId = rawBody && 'object' == typeof rawBody && 'id' in rawBody ? rawBody.id ?? null : null;
174
- if (!parseResult.success) {
175
- this._trackError('validation');
176
- responseFinalizer.finalize((response)=>{
177
- sendJsonRpcError(response, 200, -32600, 'Invalid Request', rawId, parseResult.issues);
178
- });
179
- return;
180
- }
181
- const jsonRpcRequest = parseResult.output;
199
+ const jsonRpcRequest = this._parseJsonRpcRequest(body, responseFinalizer);
200
+ if (null === jsonRpcRequest) return;
182
201
  if (!this._mcpServer) {
183
202
  this._trackError('server_not_ready');
203
+ const requestId = 'id' in jsonRpcRequest ? jsonRpcRequest.id ?? null : null;
184
204
  responseFinalizer.finalize((response)=>{
185
- sendJsonRpcError(response, 200, -32603, 'Server not ready', jsonRpcRequest.id ?? null);
205
+ sendJsonRpcError(response, 200, -32603, 'Server not ready', requestId);
186
206
  });
187
207
  return;
188
208
  }
209
+ req.off('aborted', onAborted);
189
210
  const owner = randomUUID();
190
- const response = await runWithContext({
191
- requestId: randomUUID(),
192
- owner
193
- }, ()=>this._requireMcpServer().receive(jsonRpcRequest, {
194
- sessionInfo: {}
211
+ const acceptedWork = this._acceptedWork.transfer(lease, ()=>runWithContext({
212
+ requestId: randomUUID(),
213
+ owner
214
+ }, ()=>this._requireMcpServer().receive(jsonRpcRequest, {
215
+ sessionInfo: {}
216
+ })).then((response)=>{
217
+ responseFinalizer.finalize((httpResponse)=>{
218
+ if (response) sendJsonRpcResponse(httpResponse, response);
219
+ else {
220
+ httpResponse.writeHead(204);
221
+ httpResponse.end();
222
+ }
223
+ });
224
+ }).catch((error)=>{
225
+ this._trackError('internal_error');
226
+ responseFinalizer.finalize((response)=>{
227
+ sendJsonRpcError(response, 200, -32603, 'Internal error', null, getErrorMessage(error));
228
+ });
195
229
  }));
196
- responseFinalizer.finalize((httpResponse)=>{
197
- if (response) sendJsonRpcResponse(httpResponse, response);
198
- else {
199
- httpResponse.writeHead(204);
200
- httpResponse.end();
201
- }
202
- });
230
+ await acceptedWork;
203
231
  } catch (error) {
232
+ if (lease.signal.aborted) {
233
+ if ('shutdown' === lease.cancellationReason) responseFinalizer.finalize((response)=>{
234
+ sendJsonRpcError(response, 503, -32603, 'Server is shutting down');
235
+ });
236
+ return;
237
+ }
204
238
  this._trackError('internal_error');
205
239
  responseFinalizer.finalize((response)=>{
206
240
  sendJsonRpcError(response, 200, -32603, 'Internal error', null, getErrorMessage(error));
207
241
  });
208
242
  } finally{
243
+ req.off('aborted', onAborted);
244
+ lease.release();
209
245
  clearTimeout(timeout);
210
246
  this._activeRequests--;
211
247
  }
@@ -216,6 +252,7 @@ class HttpTransport extends BaseTransport {
216
252
  stop() {
217
253
  if (this._stopPromise) return this._stopPromise;
218
254
  this._isShuttingDown = true;
255
+ this._preDispatch.closeAdmission('shutdown');
219
256
  this._stopRateLimitCleanup();
220
257
  const server = this._server;
221
258
  const serverClosed = server.listening ? new Promise((resolve, reject)=>{
@@ -226,7 +263,7 @@ class HttpTransport extends BaseTransport {
226
263
  }) : Promise.resolve();
227
264
  const stopPromise = Promise.all([
228
265
  serverClosed,
229
- this._acceptedWork.join()
266
+ this._preDispatch.join().then(()=>this._acceptedWork.join())
230
267
  ]).then(()=>{
231
268
  this.log('info', 'HTTP transport stopped');
232
269
  });
@@ -1 +1 @@
1
- {"version":3,"file":"transport/HttpTransport.js","sources":["../../src/transport/HttpTransport.ts"],"sourcesContent":["/**\n * HTTP Transport implementation.\n *\n * This transport provides a stateless, REST-like API interface for MCP tool invocations\n * using standard HTTP request-response patterns.\n *\n * @example\n * ```typescript\n * const transport = new HttpTransport({\n * port: 3000,\n * host: 'localhost'\n * });\n * await transport.connect(server);\n * ```\n */\n\nimport type { IncomingMessage, ServerResponse } from 'node:http';\nimport { createServer } from 'node:http';\nimport { randomUUID } from 'node:crypto';\nimport type { McpServer } from 'tmcp';\nimport { safeParse } from 'valibot';\nimport type { IMetrics } from '../contracts/interfaces.js';\nimport { getErrorMessage } from '../errors.js';\nimport { JsonRpcRequestSchema } from '../schema.js';\nimport { BaseTransport, type TransportOptions } from './BaseTransport.js';\nimport type { ITransport, TransportKind } from '../contracts/transport.js';\nimport {\n\treadRequestBody,\n\tsendCorsPreflight,\n\tsendJsonRpcError,\n\tsendJsonRpcResponse,\n} from './HttpHelpers.js';\nimport { runWithContext } from '../context/RequestContext.js';\nimport {\n\tAcceptedWorkTracker,\n\tLifecycleFailureReporter,\n\tResponseFinalizer,\n} from './HttpRequestLifecycle.js';\n\nexport interface HttpTransportOptions extends TransportOptions {\n\t/**\n\t * Path for messages endpoint\n\t * @default '/messages'\n\t */\n\tpath?: string;\n\tmetrics?: IMetrics;\n\tmetricsProvider?: () => string;\n\n\t/**\n\t * Enable request body size limit\n\t * @default true\n\t */\n\tenableBodySizeLimit?: boolean;\n\n\t/**\n\t * Maximum request body size in bytes\n\t * @default 10485760 (10MB)\n\t */\n\tmaxBodySize?: number;\n\n\t/**\n\t * Request timeout in milliseconds\n\t * @default 30000 (30 seconds)\n\t */\n\trequestTimeout?: number;\n}\n\n/**\n * HTTP Transport for MCP server.\n *\n * This transport provides a stateless, REST-like API interface for MCP tool invocations\n * using standard HTTP request-response patterns.\n *\n * @remarks\n * **Security Features:**\n * - Session ID validation (alphanumeric, max 64 chars)\n * - Query parameter sanitization (whitelist allowed keys)\n * - Rate limiting per IP (configurable, default 100 req/min)\n * - CORS origin validation\n * - Request body size limits (configurable, default 10MB)\n * - Request timeout (configurable, default 30s)\n *\n * **Rate Limiting:**\n * - Tracks requests per IP address within a time window\n * - Returns 429 Too Many Requests when limit exceeded\n * - Can be disabled via `enableRateLimit: false`\n *\n * **HTTP Status Code Mapping:**\n * - 200: Success (JSON-RPC response)\n * - 204: CORS Preflight (empty body)\n * - 400: Bad Request\n * - 403: Forbidden (invalid CORS)\n * - 404: Not Found\n * - 413: Payload Too Large\n * - 429: Too Many Requests\n * - 500: Internal Server Error\n * - 503: Server Not Ready\n */\nexport class HttpTransport extends BaseTransport implements ITransport {\n\tget kind(): TransportKind {\n\t\treturn 'http';\n\t}\n\tprivate _server: ReturnType<typeof createServer>;\n\tprivate _mcpServer: McpServer | null = null;\n\tprivate _requestTimeout: number;\n\tprivate _bodySizeLimitEnabled: boolean;\n\tprivate _maxBodySize: number;\n\tprivate _requestCount: number = 0;\n\tprivate _activeRequests: number = 0;\n\tprivate _path: string;\n\tprivate _metrics?: IMetrics;\n\tprivate _metricsProvider: (() => string) | null;\n\tprivate readonly _lifecycleFailureReporter: LifecycleFailureReporter;\n\tprivate readonly _acceptedWork: AcceptedWorkTracker;\n\tprivate _stopPromise: Promise<void> | null = null;\n\n\tconstructor(options: HttpTransportOptions = {}) {\n\t\tsuper(options);\n\n\t\tthis._requestTimeout = options.requestTimeout ?? 30000;\n\t\tthis._bodySizeLimitEnabled = options.enableBodySizeLimit ?? true;\n\t\tthis._maxBodySize = options.maxBodySize ?? 10 * 1024 * 1024;\n\t\tthis._path = options.path ?? '/messages';\n\t\tthis._metrics = options.metrics;\n\t\tthis._metricsProvider = options.metricsProvider ?? null;\n\t\tthis._lifecycleFailureReporter = new LifecycleFailureReporter((error) => {\n\t\t\tthis.log('error', 'HTTP request lifecycle failed', { error: getErrorMessage(error) });\n\t\t});\n\t\tthis._acceptedWork = new AcceptedWorkTracker(this._lifecycleFailureReporter);\n\t\tthis._server = createServer((req, res) => {\n\t\t\tconst responseFinalizer = new ResponseFinalizer(res, this._lifecycleFailureReporter);\n\t\t\tvoid this._handleRequest(req, res).catch((error: unknown) => {\n\t\t\t\tthis._lifecycleFailureReporter.report(error);\n\t\t\t\tresponseFinalizer.finalize((response) => {\n\t\t\t\t\tsendJsonRpcError(response, 500, -32603, 'Internal error', null, getErrorMessage(error));\n\t\t\t\t});\n\t\t\t});\n\t\t});\n\t}\n\n\tprivate _requireMcpServer(): McpServer {\n\t\tif (!this._mcpServer) {\n\t\t\tthrow new Error('MCP server not initialized. Did you call connect()?');\n\t\t}\n\t\treturn this._mcpServer;\n\t}\n\n\t/**\n\t * Get number of active HTTP connections.\n\t */\n\tget clientCount(): number {\n\t\treturn this._activeRequests;\n\t}\n\n\t/**\n\t * Connects MCP server to this transport.\n\t */\n\tasync connect(mcpServer: McpServer): Promise<void> {\n\t\tthis._mcpServer = mcpServer;\n\t\tconst server = this._server;\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tconst cleanup = (): void => {\n\t\t\t\tserver.off('error', onError);\n\t\t\t\tserver.off('listening', onListening);\n\t\t\t};\n\t\t\tconst onError = (error: Error): void => {\n\t\t\t\tcleanup();\n\t\t\t\treject(error);\n\t\t\t};\n\t\t\tconst onListening = (): void => {\n\t\t\t\tcleanup();\n\t\t\t\tthis.log('info', `HTTP transport listening on http://${this._host}:${this._port}`);\n\t\t\t\tresolve();\n\t\t\t};\n\t\t\tserver.once('error', onError);\n\t\t\tserver.once('listening', onListening);\n\t\t\ttry {\n\t\t\t\tserver.listen(this._port, this._host);\n\t\t\t} catch (error) {\n\t\t\t\tcleanup();\n\t\t\t\treject(error);\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * Track an error in metrics.\n\t */\n\tprivate _trackError(errorType: string): void {\n\t\tthis._metrics?.counter(\n\t\t\t'http_request_errors_total',\n\t\t\t1,\n\t\t\t{ transport: 'http', error_type: errorType },\n\t\t\t'Total HTTP request errors'\n\t\t);\n\t}\n\n\t/**\n\t * Route and handle incoming HTTP requests.\n\t *\n\t * Performs security checks (host, shutdown, rate limit, CORS) then\n\t * dispatches to the appropriate endpoint handler.\n\t */\n\tprivate async _handleRequest(req: IncomingMessage, res: ServerResponse): Promise<void> {\n\t\tconst startTime = Date.now();\n\t\tconst requestPath = req.url || '/';\n\t\tconst requestMethod = req.method || 'GET';\n\t\tthis._metrics?.counter('http_requests_total', 1, {}, 'Total HTTP transport requests');\n\t\tthis._metrics?.counter(\n\t\t\t'http_transport_requests_total',\n\t\t\t1,\n\t\t\t{ transport: 'http', method: requestMethod, path: requestPath },\n\t\t\t'Total HTTP requests by transport'\n\t\t);\n\t\tres.once('finish', () => {\n\t\t\tconst durationSeconds = (Date.now() - startTime) / 1000;\n\t\t\tthis._metrics?.histogram('http_request_duration_seconds', durationSeconds, {});\n\t\t\tthis._metrics?.histogram('http_transport_request_duration_seconds', durationSeconds, {\n\t\t\t\ttransport: 'http',\n\t\t\t\tpath: requestPath,\n\t\t\t});\n\t\t});\n\n\t\t// Security middleware chain\n\t\tif (!this.validateHostHeader(req)) {\n\t\t\tthis._trackError('forbidden');\n\t\t\tsendJsonRpcError(res, 403, -32000, 'Forbidden - invalid host header');\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.isShuttingDown) {\n\t\t\tthis._trackError('shutting_down');\n\t\t\tsendJsonRpcError(res, 503, -32603, 'Server is shutting down');\n\t\t\treturn;\n\t\t}\n\n\t\tconst clientIp = this.getClientIp(req);\n\t\tif (this.checkRateLimit(clientIp)) {\n\t\t\tthis._trackError('rate_limit');\n\t\t\tres.setHeader('Retry-After', '60');\n\t\t\tsendJsonRpcError(res, 429, -32000, 'Too many requests');\n\t\t\treturn;\n\t\t}\n\n\t\tif (!this.validateCorsOrigin(req)) {\n\t\t\tthis._trackError('forbidden');\n\t\t\tsendJsonRpcError(res, 403, -32000, 'Forbidden - invalid origin');\n\t\t\treturn;\n\t\t}\n\n\t\tthis.setCorsHeaders(res);\n\n\t\t// Static endpoints\n\t\tif (req.method === 'GET' && req.url === '/metrics')\n\t\t\treturn this.handleMetricsEndpoint(res, this._metricsProvider);\n\t\tif (req.method === 'OPTIONS') return sendCorsPreflight(res);\n\t\tif (req.method === 'GET' && req.url === '/health')\n\t\t\treturn this.handleHealthEndpoint(res, { requests: this._requestCount });\n\t\tif (req.method === 'GET' && req.url === '/ready') return this.handleReadinessEndpoint(res);\n\n\t\t// MCP endpoint\n\t\tif (req.method === 'POST' && req.url === this._path) {\n\t\t\tthis._acceptedWork.track(this._handlePostRequest(req, res));\n\t\t\treturn;\n\t\t}\n\n\t\t// 404\n\t\tthis._trackError('not_found');\n\t\tsendJsonRpcError(res, 404, -32601, 'Not Found');\n\t}\n\n\t/**\n\t * Handle POST to the MCP messages endpoint.\n\t *\n\t * Reads the request body, validates JSON-RPC format, and delegates\n\t * processing to the MCP server.\n\t */\n\tprivate async _handlePostRequest(req: IncomingMessage, res: ServerResponse): Promise<void> {\n\t\tthis._requestCount++;\n\t\tthis._activeRequests++;\n\t\tconst responseFinalizer = new ResponseFinalizer(res, this._lifecycleFailureReporter);\n\n\t\tconst timeout = setTimeout(() => {\n\t\t\tthis._trackError('timeout');\n\t\t\tresponseFinalizer.finalize((response) => {\n\t\t\t\tsendJsonRpcError(response, 500, -32603, 'Request timeout');\n\t\t\t});\n\t\t}, this._requestTimeout);\n\n\t\ttry {\n\t\t\tconst maxBodySize = this._bodySizeLimitEnabled ? this._maxBodySize : 0;\n\t\t\tconst body = await readRequestBody(req, maxBodySize);\n\n\t\t\tif (body === null) {\n\t\t\t\tthis._trackError('payload_too_large');\n\t\t\t\tresponseFinalizer.finalize((response) => {\n\t\t\t\t\tsendJsonRpcError(response, 413, -32000, 'Request body too large');\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tlet rawBody: unknown;\n\t\t\ttry {\n\t\t\t\trawBody = JSON.parse(body) as unknown;\n\t\t\t} catch {\n\t\t\t\tthis._trackError('parse_error');\n\t\t\t\tresponseFinalizer.finalize((response) => {\n\t\t\t\t\tsendJsonRpcError(response, 200, -32700, 'Parse error');\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst parseResult = safeParse(JsonRpcRequestSchema, rawBody);\n\t\t\tconst rawId =\n\t\t\t\trawBody && typeof rawBody === 'object' && 'id' in rawBody\n\t\t\t\t\t? ((rawBody as { id?: unknown }).id ?? null)\n\t\t\t\t\t: null;\n\t\t\tif (!parseResult.success) {\n\t\t\t\tthis._trackError('validation');\n\t\t\t\tresponseFinalizer.finalize((response) => {\n\t\t\t\t\tsendJsonRpcError(\n\t\t\t\t\t\tresponse,\n\t\t\t\t\t\t200,\n\t\t\t\t\t\t-32600,\n\t\t\t\t\t\t'Invalid Request',\n\t\t\t\t\t\trawId as string | number | null,\n\t\t\t\t\t\tparseResult.issues\n\t\t\t\t\t);\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst jsonRpcRequest = parseResult.output;\n\n\t\t\tif (!this._mcpServer) {\n\t\t\t\tthis._trackError('server_not_ready');\n\t\t\t\tresponseFinalizer.finalize((response) => {\n\t\t\t\t\tsendJsonRpcError(response, 200, -32603, 'Server not ready', jsonRpcRequest.id ?? null);\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst owner = randomUUID();\n\t\t\tconst response = await runWithContext({ requestId: randomUUID(), owner }, () =>\n\t\t\t\tthis._requireMcpServer().receive(jsonRpcRequest as Parameters<McpServer['receive']>[0], {\n\t\t\t\t\tsessionInfo: {},\n\t\t\t\t})\n\t\t\t);\n\n\t\t\tresponseFinalizer.finalize((httpResponse) => {\n\t\t\t\tif (response) {\n\t\t\t\t\tsendJsonRpcResponse(httpResponse, response);\n\t\t\t\t} else {\n\t\t\t\t\thttpResponse.writeHead(204);\n\t\t\t\t\thttpResponse.end();\n\t\t\t\t}\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tthis._trackError('internal_error');\n\t\t\tresponseFinalizer.finalize((response) => {\n\t\t\t\tsendJsonRpcError(response, 200, -32603, 'Internal error', null, getErrorMessage(error));\n\t\t\t});\n\t\t} finally {\n\t\t\tclearTimeout(timeout);\n\t\t\tthis._activeRequests--;\n\t\t}\n\t}\n\n\t/**\n\t * Returns number of requests handled.\n\t */\n\tget requestCount(): number {\n\t\treturn this._requestCount;\n\t}\n\n\t/**\n\t * Stops transport server.\n\t */\n\tstop(): Promise<void> {\n\t\tif (this._stopPromise) return this._stopPromise;\n\t\tthis._isShuttingDown = true;\n\t\tthis._stopRateLimitCleanup();\n\n\t\tconst server = this._server;\n\t\tconst serverClosed = server.listening\n\t\t\t? new Promise<void>((resolve, reject) => {\n\t\t\t\t\tserver.close((error) => {\n\t\t\t\t\t\tif (error) {\n\t\t\t\t\t\t\treject(error);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tresolve();\n\t\t\t\t\t});\n\t\t\t\t})\n\t\t\t: Promise.resolve();\n\t\tconst stopPromise = Promise.all([serverClosed, this._acceptedWork.join()]).then(() => {\n\t\t\tthis.log('info', 'HTTP transport stopped');\n\t\t});\n\t\tthis._stopPromise = stopPromise;\n\t\tvoid stopPromise.catch(() => {\n\t\t\tif (this._stopPromise === stopPromise) this._stopPromise = null;\n\t\t});\n\t\treturn stopPromise;\n\t}\n}\n\n/**\n * Create an HTTP transport with given options.\n *\n * @param options - Transport configuration\n * @returns A configured HTTP transport\n *\n * @example\n * ```typescript\n * const transport = new HttpTransport({ port: 3000 });\n * await transport.connect(server);\n * ```\n */\nexport function createHttpTransport(options: HttpTransportOptions = {}): HttpTransport {\n\treturn new HttpTransport(options);\n}\n"],"names":["HttpTransport","BaseTransport","options","LifecycleFailureReporter","error","getErrorMessage","AcceptedWorkTracker","createServer","req","res","responseFinalizer","ResponseFinalizer","response","sendJsonRpcError","Error","mcpServer","server","Promise","resolve","reject","cleanup","onError","onListening","errorType","startTime","Date","requestPath","requestMethod","durationSeconds","clientIp","sendCorsPreflight","timeout","setTimeout","maxBodySize","body","readRequestBody","rawBody","JSON","parseResult","safeParse","JsonRpcRequestSchema","rawId","jsonRpcRequest","owner","randomUUID","runWithContext","httpResponse","sendJsonRpcResponse","clearTimeout","serverClosed","stopPromise","createHttpTransport"],"mappings":"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"}
1
+ {"version":3,"file":"transport/HttpTransport.js","sources":["../../src/transport/HttpTransport.ts"],"sourcesContent":["/**\n * HTTP Transport implementation.\n *\n * This transport provides a stateless, REST-like API interface for MCP tool invocations\n * using standard HTTP request-response patterns.\n *\n * @example\n * ```typescript\n * const transport = new HttpTransport({\n * port: 3000,\n * host: 'localhost'\n * });\n * await transport.connect(server);\n * ```\n */\n\nimport type { IncomingMessage, ServerResponse } from 'node:http';\nimport { createServer } from 'node:http';\nimport { randomUUID } from 'node:crypto';\nimport type { McpServer } from 'tmcp';\nimport { safeParse } from 'valibot';\nimport type { IMetrics } from '../contracts/interfaces.js';\nimport { getErrorMessage } from '../errors.js';\nimport { JsonRpcRequestSchema } from '../schema.js';\nimport { BaseTransport, type TransportOptions } from './BaseTransport.js';\nimport type { ITransport, TransportKind } from '../contracts/transport.js';\nimport {\n\treadRequestBody,\n\tsendCorsPreflight,\n\tsendJsonRpcError,\n\tsendJsonRpcResponse,\n} from './HttpHelpers.js';\nimport { runWithContext } from '../context/RequestContext.js';\nimport {\n\tAcceptedWorkTracker,\n\tLifecycleFailureReporter,\n\tPreDispatchTracker,\n\tResponseFinalizer,\n\ttype PreDispatchLease,\n} from './HttpRequestLifecycle.js';\n\nexport interface HttpTransportOptions extends TransportOptions {\n\t/**\n\t * Path for messages endpoint\n\t * @default '/messages'\n\t */\n\tpath?: string;\n\tmetrics?: IMetrics;\n\tmetricsProvider?: () => string;\n\n\t/**\n\t * Enable request body size limit\n\t * @default true\n\t */\n\tenableBodySizeLimit?: boolean;\n\n\t/**\n\t * Maximum request body size in bytes\n\t * @default 10485760 (10MB)\n\t */\n\tmaxBodySize?: number;\n\n\t/**\n\t * Request timeout in milliseconds\n\t * @default 30000 (30 seconds)\n\t */\n\trequestTimeout?: number;\n}\n\n/**\n * HTTP Transport for MCP server.\n *\n * This transport provides a stateless, REST-like API interface for MCP tool invocations\n * using standard HTTP request-response patterns.\n *\n * @remarks\n * **Security Features:**\n * - Session ID validation (alphanumeric, max 64 chars)\n * - Query parameter sanitization (whitelist allowed keys)\n * - Rate limiting per IP (configurable, default 100 req/min)\n * - CORS origin validation\n * - Request body size limits (configurable, default 10MB)\n * - Request timeout (configurable, default 30s)\n *\n * **Rate Limiting:**\n * - Tracks requests per IP address within a time window\n * - Returns 429 Too Many Requests when limit exceeded\n * - Can be disabled via `enableRateLimit: false`\n *\n * **HTTP Status Code Mapping:**\n * - 200: Success (JSON-RPC response)\n * - 204: CORS Preflight (empty body)\n * - 400: Bad Request\n * - 403: Forbidden (invalid CORS)\n * - 404: Not Found\n * - 413: Payload Too Large\n * - 429: Too Many Requests\n * - 500: Internal Server Error\n * - 503: Server Not Ready\n */\nexport class HttpTransport extends BaseTransport implements ITransport {\n\tget kind(): TransportKind {\n\t\treturn 'http';\n\t}\n\tprivate _server: ReturnType<typeof createServer>;\n\tprivate _mcpServer: McpServer | null = null;\n\tprivate _requestTimeout: number;\n\tprivate _bodySizeLimitEnabled: boolean;\n\tprivate _maxBodySize: number;\n\tprivate _requestCount: number = 0;\n\tprivate _activeRequests: number = 0;\n\tprivate _path: string;\n\tprivate _metrics?: IMetrics;\n\tprivate _metricsProvider: (() => string) | null;\n\tprivate readonly _lifecycleFailureReporter: LifecycleFailureReporter;\n\tprivate readonly _acceptedWork: AcceptedWorkTracker;\n\tprivate readonly _preDispatch = new PreDispatchTracker();\n\tprivate _stopPromise: Promise<void> | null = null;\n\n\tconstructor(options: HttpTransportOptions = {}) {\n\t\tsuper(options);\n\n\t\tthis._requestTimeout = options.requestTimeout ?? 30000;\n\t\tthis._bodySizeLimitEnabled = options.enableBodySizeLimit ?? true;\n\t\tthis._maxBodySize = options.maxBodySize ?? 10 * 1024 * 1024;\n\t\tthis._path = options.path ?? '/messages';\n\t\tthis._metrics = options.metrics;\n\t\tthis._metricsProvider = options.metricsProvider ?? null;\n\t\tthis._lifecycleFailureReporter = new LifecycleFailureReporter((error) => {\n\t\t\tthis.log('error', 'HTTP request lifecycle failed', { error: getErrorMessage(error) });\n\t\t});\n\t\tthis._acceptedWork = new AcceptedWorkTracker(this._lifecycleFailureReporter);\n\t\tthis._server = createServer((req, res) => {\n\t\t\tconst responseFinalizer = new ResponseFinalizer(res, this._lifecycleFailureReporter);\n\t\t\tvoid this._handleRequest(req, res).catch((error: unknown) => {\n\t\t\t\tthis._lifecycleFailureReporter.report(error);\n\t\t\t\tresponseFinalizer.finalize((response) => {\n\t\t\t\t\tsendJsonRpcError(response, 500, -32603, 'Internal error', null, getErrorMessage(error));\n\t\t\t\t});\n\t\t\t});\n\t\t});\n\t}\n\n\tprivate _requireMcpServer(): McpServer {\n\t\tif (!this._mcpServer) {\n\t\t\tthrow new Error('MCP server not initialized. Did you call connect()?');\n\t\t}\n\t\treturn this._mcpServer;\n\t}\n\n\t/**\n\t * Get number of active HTTP connections.\n\t */\n\tget clientCount(): number {\n\t\treturn this._activeRequests;\n\t}\n\n\t/**\n\t * Connects MCP server to this transport.\n\t */\n\tasync connect(mcpServer: McpServer): Promise<void> {\n\t\tthis._mcpServer = mcpServer;\n\t\tconst server = this._server;\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tconst cleanup = (): void => {\n\t\t\t\tserver.off('error', onError);\n\t\t\t\tserver.off('listening', onListening);\n\t\t\t};\n\t\t\tconst onError = (error: Error): void => {\n\t\t\t\tcleanup();\n\t\t\t\treject(error);\n\t\t\t};\n\t\t\tconst onListening = (): void => {\n\t\t\t\tcleanup();\n\t\t\t\tthis.log('info', `HTTP transport listening on http://${this._host}:${this._port}`);\n\t\t\t\tresolve();\n\t\t\t};\n\t\t\tserver.once('error', onError);\n\t\t\tserver.once('listening', onListening);\n\t\t\ttry {\n\t\t\t\tserver.listen(this._port, this._host);\n\t\t\t} catch (error) {\n\t\t\t\tcleanup();\n\t\t\t\treject(error);\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * Track an error in metrics.\n\t */\n\tprivate _trackError(errorType: string): void {\n\t\tthis._metrics?.counter(\n\t\t\t'http_request_errors_total',\n\t\t\t1,\n\t\t\t{ transport: 'http', error_type: errorType },\n\t\t\t'Total HTTP request errors'\n\t\t);\n\t}\n\n\tprivate _parseJsonRpcRequest(\n\t\tbody: string,\n\t\tresponseFinalizer: ResponseFinalizer\n\t): Parameters<McpServer['receive']>[0] | null {\n\t\tlet rawBody: unknown;\n\t\ttry {\n\t\t\trawBody = JSON.parse(body) as unknown;\n\t\t} catch {\n\t\t\tthis._trackError('parse_error');\n\t\t\tresponseFinalizer.finalize((response) => {\n\t\t\t\tsendJsonRpcError(response, 200, -32700, 'Parse error');\n\t\t\t});\n\t\t\treturn null;\n\t\t}\n\n\t\tconst parseResult = safeParse(JsonRpcRequestSchema, rawBody);\n\t\tconst rawId =\n\t\t\trawBody && typeof rawBody === 'object' && 'id' in rawBody\n\t\t\t\t? ((rawBody as { id?: unknown }).id ?? null)\n\t\t\t\t: null;\n\t\tif (!parseResult.success) {\n\t\t\tthis._trackError('validation');\n\t\t\tresponseFinalizer.finalize((response) => {\n\t\t\t\tsendJsonRpcError(\n\t\t\t\t\tresponse,\n\t\t\t\t\t200,\n\t\t\t\t\t-32600,\n\t\t\t\t\t'Invalid Request',\n\t\t\t\t\trawId as string | number | null,\n\t\t\t\t\tparseResult.issues\n\t\t\t\t);\n\t\t\t});\n\t\t\treturn null;\n\t\t}\n\t\treturn parseResult.output as Parameters<McpServer['receive']>[0];\n\t}\n\n\t/**\n\t * Route and handle incoming HTTP requests.\n\t *\n\t * Performs security checks (host, shutdown, rate limit, CORS) then\n\t * dispatches to the appropriate endpoint handler.\n\t */\n\tprivate async _handleRequest(req: IncomingMessage, res: ServerResponse): Promise<void> {\n\t\tconst startTime = Date.now();\n\t\tconst requestPath = req.url || '/';\n\t\tconst requestMethod = req.method || 'GET';\n\t\tthis._metrics?.counter('http_requests_total', 1, {}, 'Total HTTP transport requests');\n\t\tthis._metrics?.counter(\n\t\t\t'http_transport_requests_total',\n\t\t\t1,\n\t\t\t{ transport: 'http', method: requestMethod, path: requestPath },\n\t\t\t'Total HTTP requests by transport'\n\t\t);\n\t\tres.once('finish', () => {\n\t\t\tconst durationSeconds = (Date.now() - startTime) / 1000;\n\t\t\tthis._metrics?.histogram('http_request_duration_seconds', durationSeconds, {});\n\t\t\tthis._metrics?.histogram('http_transport_request_duration_seconds', durationSeconds, {\n\t\t\t\ttransport: 'http',\n\t\t\t\tpath: requestPath,\n\t\t\t});\n\t\t});\n\n\t\t// Security middleware chain\n\t\tif (!this.validateHostHeader(req)) {\n\t\t\tthis._trackError('forbidden');\n\t\t\tsendJsonRpcError(res, 403, -32000, 'Forbidden - invalid host header');\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.isShuttingDown) {\n\t\t\tthis._trackError('shutting_down');\n\t\t\tsendJsonRpcError(res, 503, -32603, 'Server is shutting down');\n\t\t\treturn;\n\t\t}\n\n\t\tconst clientIp = this.getClientIp(req);\n\t\tif (this.checkRateLimit(clientIp)) {\n\t\t\tthis._trackError('rate_limit');\n\t\t\tres.setHeader('Retry-After', '60');\n\t\t\tsendJsonRpcError(res, 429, -32000, 'Too many requests');\n\t\t\treturn;\n\t\t}\n\n\t\tif (!this.validateCorsOrigin(req)) {\n\t\t\tthis._trackError('forbidden');\n\t\t\tsendJsonRpcError(res, 403, -32000, 'Forbidden - invalid origin');\n\t\t\treturn;\n\t\t}\n\n\t\tthis.setCorsHeaders(res);\n\n\t\t// Static endpoints\n\t\tif (req.method === 'GET' && req.url === '/metrics')\n\t\t\treturn this.handleMetricsEndpoint(res, this._metricsProvider);\n\t\tif (req.method === 'OPTIONS') return sendCorsPreflight(res);\n\t\tif (req.method === 'GET' && req.url === '/health')\n\t\t\treturn this.handleHealthEndpoint(res, { requests: this._requestCount });\n\t\tif (req.method === 'GET' && req.url === '/ready') return this.handleReadinessEndpoint(res);\n\n\t\t// MCP endpoint\n\t\tif (req.method === 'POST' && req.url === this._path) {\n\t\t\tconst lease = this._preDispatch.acquire();\n\t\t\tif (!lease) {\n\t\t\t\tconst responseFinalizer = new ResponseFinalizer(res, this._lifecycleFailureReporter);\n\t\t\t\tresponseFinalizer.finalize((response) => {\n\t\t\t\t\tsendJsonRpcError(response, 503, -32603, 'Server is shutting down');\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tawait this._handlePostRequest(req, res, lease);\n\t\t\treturn;\n\t\t}\n\n\t\t// 404\n\t\tthis._trackError('not_found');\n\t\tsendJsonRpcError(res, 404, -32601, 'Not Found');\n\t}\n\n\t/**\n\t * Handle POST to the MCP messages endpoint.\n\t *\n\t * Reads the request body, validates JSON-RPC format, and delegates\n\t * processing to the MCP server.\n\t */\n\tprivate async _handlePostRequest(\n\t\treq: IncomingMessage,\n\t\tres: ServerResponse,\n\t\tlease: PreDispatchLease\n\t): Promise<void> {\n\t\tthis._requestCount++;\n\t\tthis._activeRequests++;\n\t\tconst responseFinalizer = new ResponseFinalizer(res, this._lifecycleFailureReporter);\n\t\tconst onAborted = (): void => lease.cancel('peer');\n\t\treq.once('aborted', onAborted);\n\n\t\tconst timeout = setTimeout(() => {\n\t\t\tthis._trackError('timeout');\n\t\t\tresponseFinalizer.finalize((response) => {\n\t\t\t\tsendJsonRpcError(response, 500, -32603, 'Request timeout');\n\t\t\t});\n\t\t\tlease.cancel('timeout');\n\t\t}, this._requestTimeout);\n\n\t\ttry {\n\t\t\tconst maxBodySize = this._bodySizeLimitEnabled ? this._maxBodySize : 0;\n\t\t\tconst body = await readRequestBody(req, maxBodySize, lease.signal);\n\n\t\t\tif (body === null) {\n\t\t\t\tthis._trackError('payload_too_large');\n\t\t\t\tresponseFinalizer.finalize((response) => {\n\t\t\t\t\tsendJsonRpcError(response, 413, -32000, 'Request body too large');\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst jsonRpcRequest = this._parseJsonRpcRequest(body, responseFinalizer);\n\t\t\tif (jsonRpcRequest === null) return;\n\n\t\t\tif (!this._mcpServer) {\n\t\t\t\tthis._trackError('server_not_ready');\n\t\t\t\tconst requestId = 'id' in jsonRpcRequest ? (jsonRpcRequest.id ?? null) : null;\n\t\t\t\tresponseFinalizer.finalize((response) => {\n\t\t\t\t\tsendJsonRpcError(response, 200, -32603, 'Server not ready', requestId);\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\treq.off('aborted', onAborted);\n\t\t\tconst owner = randomUUID();\n\t\t\tconst acceptedWork = this._acceptedWork.transfer(lease, () =>\n\t\t\t\trunWithContext({ requestId: randomUUID(), owner }, () =>\n\t\t\t\t\tthis._requireMcpServer().receive(jsonRpcRequest, {\n\t\t\t\t\t\tsessionInfo: {},\n\t\t\t\t\t})\n\t\t\t\t)\n\t\t\t\t\t.then((response: Awaited<ReturnType<McpServer['receive']>>) => {\n\t\t\t\t\t\tresponseFinalizer.finalize((httpResponse) => {\n\t\t\t\t\t\t\tif (response) {\n\t\t\t\t\t\t\t\tsendJsonRpcResponse(httpResponse, response);\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\thttpResponse.writeHead(204);\n\t\t\t\t\t\t\t\thttpResponse.end();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\t\t\t\t\t})\n\t\t\t\t\t.catch((error: unknown) => {\n\t\t\t\t\t\tthis._trackError('internal_error');\n\t\t\t\t\t\tresponseFinalizer.finalize((response) => {\n\t\t\t\t\t\t\tsendJsonRpcError(\n\t\t\t\t\t\t\t\tresponse,\n\t\t\t\t\t\t\t\t200,\n\t\t\t\t\t\t\t\t-32603,\n\t\t\t\t\t\t\t\t'Internal error',\n\t\t\t\t\t\t\t\tnull,\n\t\t\t\t\t\t\t\tgetErrorMessage(error)\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t});\n\t\t\t\t\t})\n\t\t\t);\n\t\t\tawait acceptedWork;\n\t\t} catch (error) {\n\t\t\tif (lease.signal.aborted) {\n\t\t\t\tif (lease.cancellationReason === 'shutdown') {\n\t\t\t\t\tresponseFinalizer.finalize((response) => {\n\t\t\t\t\t\tsendJsonRpcError(response, 503, -32603, 'Server is shutting down');\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis._trackError('internal_error');\n\t\t\tresponseFinalizer.finalize((response) => {\n\t\t\t\tsendJsonRpcError(response, 200, -32603, 'Internal error', null, getErrorMessage(error));\n\t\t\t});\n\t\t} finally {\n\t\t\treq.off('aborted', onAborted);\n\t\t\tlease.release();\n\t\t\tclearTimeout(timeout);\n\t\t\tthis._activeRequests--;\n\t\t}\n\t}\n\n\t/**\n\t * Returns number of requests handled.\n\t */\n\tget requestCount(): number {\n\t\treturn this._requestCount;\n\t}\n\n\t/**\n\t * Stops transport server.\n\t */\n\tstop(): Promise<void> {\n\t\tif (this._stopPromise) return this._stopPromise;\n\t\tthis._isShuttingDown = true;\n\t\tthis._preDispatch.closeAdmission('shutdown');\n\t\tthis._stopRateLimitCleanup();\n\n\t\tconst server = this._server;\n\t\tconst serverClosed = server.listening\n\t\t\t? new Promise<void>((resolve, reject) => {\n\t\t\t\t\tserver.close((error) => {\n\t\t\t\t\t\tif (error) {\n\t\t\t\t\t\t\treject(error);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tresolve();\n\t\t\t\t\t});\n\t\t\t\t})\n\t\t\t: Promise.resolve();\n\t\tconst stopPromise = Promise.all([\n\t\t\tserverClosed,\n\t\t\tthis._preDispatch.join().then(() => this._acceptedWork.join()),\n\t\t]).then(() => {\n\t\t\tthis.log('info', 'HTTP transport stopped');\n\t\t});\n\t\tthis._stopPromise = stopPromise;\n\t\tvoid stopPromise.catch(() => {\n\t\t\tif (this._stopPromise === stopPromise) this._stopPromise = null;\n\t\t});\n\t\treturn stopPromise;\n\t}\n}\n\n/**\n * Create an HTTP transport with given options.\n *\n * @param options - Transport configuration\n * @returns A configured HTTP transport\n *\n * @example\n * ```typescript\n * const transport = new HttpTransport({ port: 3000 });\n * await transport.connect(server);\n * ```\n */\nexport function createHttpTransport(options: HttpTransportOptions = {}): HttpTransport {\n\treturn new HttpTransport(options);\n}\n"],"names":["HttpTransport","BaseTransport","PreDispatchTracker","options","LifecycleFailureReporter","error","getErrorMessage","AcceptedWorkTracker","createServer","req","res","responseFinalizer","ResponseFinalizer","response","sendJsonRpcError","Error","mcpServer","server","Promise","resolve","reject","cleanup","onError","onListening","errorType","body","rawBody","JSON","parseResult","safeParse","JsonRpcRequestSchema","rawId","startTime","Date","requestPath","requestMethod","durationSeconds","clientIp","sendCorsPreflight","lease","onAborted","timeout","setTimeout","maxBodySize","readRequestBody","jsonRpcRequest","requestId","owner","randomUUID","acceptedWork","runWithContext","httpResponse","sendJsonRpcResponse","clearTimeout","serverClosed","stopPromise","createHttpTransport"],"mappings":"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"}
@@ -1,12 +1,8 @@
1
1
  /**
2
2
  * Streamable HTTP Transport implementation (MCP spec recommended transport).
3
3
  *
4
- * This transport implements the MCP Streamable HTTP specification, which replaces
5
- * the deprecated SSE transport as the recommended HTTP-based transport since March 2025.
6
- *
7
4
  * Key features:
8
5
  * - POST /mcp for JSON-RPC requests (main MCP endpoint)
9
- * - GET /mcp for optional SSE server-to-client notifications
10
6
  * - Session management via Mcp-Session-Id header
11
7
  * - Supports both stateful (session-based) and stateless (per-request) modes
12
8
  * - Health endpoints (/health, /ready)
@@ -80,8 +76,7 @@ export interface StreamableHttpTransportOptions extends TransportOptions {
80
76
  * Streamable HTTP Transport for MCP server.
81
77
  *
82
78
  * This transport implements the MCP Streamable HTTP specification,
83
- * providing JSON-RPC over HTTP with optional session management
84
- * and server-to-client SSE notification streams.
79
+ * providing JSON-RPC over HTTP with optional session management.
85
80
  *
86
81
  * @remarks
87
82
  * **Security Features (inherited from BaseTransport):**
@@ -93,13 +88,11 @@ export interface StreamableHttpTransportOptions extends TransportOptions {
93
88
  *
94
89
  * **MCP Streamable HTTP Spec Compliance:**
95
90
  * - POST /mcp — JSON-RPC method calls
96
- * - GET /mcp — SSE notification stream (server-to-client)
97
91
  * - Mcp-Session-Id header for session management
98
92
  * - Content-Type: application/json for JSON-RPC responses
99
- * - Content-Type: text/event-stream for SSE notification streams
100
93
  *
101
94
  * **HTTP Status Code Mapping:**
102
- * - 200: Success (JSON-RPC response or SSE stream)
95
+ * - 200: Success (JSON-RPC response)
103
96
  * - 202: Accepted (JSON-RPC notification, no response body)
104
97
  * - 204: CORS Preflight (empty body)
105
98
  * - 400: Bad Request (invalid JSON, invalid session ID)
@@ -128,6 +121,7 @@ export declare class StreamableHttpTransport extends BaseTransport implements IT
128
121
  private _metricsProvider;
129
122
  private readonly _lifecycleFailureReporter;
130
123
  private readonly _acceptedWork;
124
+ private readonly _preDispatch;
131
125
  private readonly _sessionRetention;
132
126
  private _sessionSweepIntervalId;
133
127
  private _stopPromise;
@@ -145,6 +139,7 @@ export declare class StreamableHttpTransport extends BaseTransport implements IT
145
139
  * Connects MCP server to this transport and starts listening.
146
140
  */
147
141
  connect(mcpServer: McpServer): Promise<void>;
142
+ private _recordRequestMetrics;
148
143
  /**
149
144
  * Route and handle incoming HTTP requests.
150
145
  */
@@ -153,6 +148,7 @@ export declare class StreamableHttpTransport extends BaseTransport implements IT
153
148
  * Send a JSON-RPC error response.
154
149
  */
155
150
  private _sendJsonRpcError;
151
+ private _parseJsonRpcRequest;
156
152
  /**
157
153
  * Handle POST /mcp — JSON-RPC method calls.
158
154
  *
@@ -165,14 +161,6 @@ export declare class StreamableHttpTransport extends BaseTransport implements IT
165
161
  private _handleMcpPost;
166
162
  private _acceptPostSession;
167
163
  private _receiveAndFinalize;
168
- /**
169
- * Handle GET /mcp — Optional SSE notification stream.
170
- *
171
- * Per the MCP Streamable HTTP spec, clients may open a GET request
172
- * to receive server-initiated notifications as SSE events.
173
- * Requires a valid Mcp-Session-Id in stateful mode.
174
- */
175
- private _handleMcpGet;
176
164
  /**
177
165
  * Resolve or create a session for a stateful request.
178
166
  *
@@ -186,18 +174,6 @@ export declare class StreamableHttpTransport extends BaseTransport implements IT
186
174
  * Extract Mcp-Session-Id from request headers.
187
175
  */
188
176
  private _getSessionIdFromHeader;
189
- /**
190
- * Send an SSE event to a specific client response stream.
191
- */
192
- private _sendSseEvent;
193
- /**
194
- * Broadcast a notification to all SSE streams in a given session.
195
- *
196
- * @param sessionId - Target session ID
197
- * @param event - SSE event name
198
- * @param data - Event payload
199
- */
200
- broadcastToSession(sessionId: string, event: string, data: unknown): void;
201
177
  /**
202
178
  * Handle GET /metrics endpoint.
203
179
  */
@@ -1 +1 @@
1
- {"version":3,"file":"StreamableHttpTransport.d.ts","sourceRoot":"","sources":["../../src/transport/StreamableHttpTransport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAIH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AAEtC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AAG3D,OAAO,EAAE,aAAa,EAAE,KAAK,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC1E,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAU3E;;GAEG;AACH,MAAM,WAAW,8BAA+B,SAAQ,gBAAgB;IACvE;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,OAAO,CAAC,EAAE,QAAQ,CAAC;IAEnB;;OAEG;IACH,eAAe,CAAC,EAAE,MAAM,MAAM,CAAC;IAE/B;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB;;;OAGG;IACH,kBAAkB,CAAC,EAAE,MAAM,MAAM,CAAC;IAElC;;;OAGG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAE9B;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB,6DAA6D;IAC7D,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,wDAAwD;IACxD,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAE9B,4CAA4C;IAC5C,sBAAsB,CAAC,EAAE,MAAM,CAAC;CAChC;AAsED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,qBAAa,uBAAwB,SAAQ,aAAc,YAAW,UAAU;IAC/E,IAAI,IAAI,IAAI,aAAa,CAExB;IACD,OAAO,CAAC,OAAO,CAAuB;IACtC,OAAO,CAAC,UAAU,CAA0B;IAC5C,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,SAAS,CAAU;IAC3B,OAAO,CAAC,mBAAmB,CAAe;IAC1C,OAAO,CAAC,SAAS,CAA2C;IAC5D,OAAO,CAAC,aAAa,CAAa;IAClC,OAAO,CAAC,eAAe,CAAa;IACpC,OAAO,CAAC,qBAAqB,CAAU;IACvC,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,eAAe,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,CAAW;IAC5B,OAAO,CAAC,gBAAgB,CAAwB;IAChD,OAAO,CAAC,QAAQ,CAAC,yBAAyB,CAA2B;IACrE,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAsB;IACpD,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAiC;IACnE,OAAO,CAAC,uBAAuB,CAA+B;IAC9D,OAAO,CAAC,YAAY,CAA8B;gBAEtC,OAAO,GAAE,8BAAmC;IA4BxD,OAAO,CAAC,iBAAiB;IAOzB;;OAEG;IACH,IAAI,WAAW,IAAI,MAAM,CAExB;IAED;;OAEG;IACH,IAAI,YAAY,IAAI,MAAM,CAEzB;IAED;;OAEG;IACG,OAAO,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IA2ClD;;OAEG;YACW,cAAc;IA+F5B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAgBzB;;;;;;;;OAQG;YACW,cAAc;IAyF5B,OAAO,CAAC,kBAAkB;YAsBZ,mBAAmB;IAwBjC;;;;;;OAMG;IACH,OAAO,CAAC,aAAa;IAsErB;;;;OAIG;IACH,OAAO,CAAC,eAAe;IA8CvB,OAAO,CAAC,qBAAqB;IAa7B,OAAO,CAAC,eAAe;IAevB,OAAO,CAAC,iBAAiB;IAQzB;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAQ/B;;OAEG;IACH,OAAO,CAAC,aAAa;IASrB;;;;;;OAMG;IACH,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI;IAWzE;;OAEG;IACH,OAAO,CAAC,cAAc;IAWtB;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAe1B;;OAEG;YACW,qBAAqB;IAkBnC;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAoB7B;;;;OAIG;IACH,IAAI,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAiDrC;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,6BAA6B,CAC5C,OAAO,GAAE,8BAAmC,GAC1C,uBAAuB,CAEzB"}
1
+ {"version":3,"file":"StreamableHttpTransport.d.ts","sourceRoot":"","sources":["../../src/transport/StreamableHttpTransport.ts"],"names":[],"mappings":"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"}