@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.
- package/README.md +88 -64
- package/dist/ServerConfig.d.ts +1 -1
- package/dist/ServerConfig.js.map +1 -1
- package/dist/cli.js +223 -254
- package/dist/cli.js.map +1 -1
- package/dist/config/ConfigLoader.d.ts +29 -26
- package/dist/config/ConfigLoader.d.ts.map +1 -1
- package/dist/config/ConfigLoader.js +40 -36
- package/dist/config/ConfigLoader.js.map +1 -1
- package/dist/contracts/PersistenceBackend.d.ts +7 -108
- package/dist/contracts/PersistenceBackend.d.ts.map +1 -1
- package/dist/contracts/PersistenceBackend.js +1 -6
- package/dist/contracts/calibrator.d.ts +6 -6
- package/dist/contracts/calibrator.d.ts.map +1 -1
- package/dist/contracts/ids.d.ts +1 -8
- package/dist/contracts/ids.d.ts.map +1 -1
- package/dist/contracts/ids.js +2 -3
- package/dist/contracts/ids.js.map +1 -1
- package/dist/contracts/interfaces.d.ts +4 -6
- package/dist/contracts/interfaces.d.ts.map +1 -1
- package/dist/contracts/persistence-work.d.ts +2 -3
- package/dist/contracts/persistence-work.d.ts.map +1 -1
- package/dist/contracts/summary.d.ts +0 -1
- package/dist/contracts/summary.d.ts.map +1 -1
- package/dist/core/HistoryManager.d.ts +12 -16
- package/dist/core/HistoryManager.d.ts.map +1 -1
- package/dist/core/HistoryManager.js +19 -40
- package/dist/core/HistoryManager.js.map +1 -1
- package/dist/core/IHistoryManager.d.ts +22 -30
- package/dist/core/IHistoryManager.d.ts.map +1 -1
- package/dist/core/InputNormalizer.d.ts +7 -24
- package/dist/core/InputNormalizer.d.ts.map +1 -1
- package/dist/core/InputNormalizer.js +3 -9
- package/dist/core/InputNormalizer.js.map +1 -1
- package/dist/core/PersistenceBuffer.d.ts +3 -20
- package/dist/core/PersistenceBuffer.d.ts.map +1 -1
- package/dist/core/PersistenceBuffer.js +1 -4
- package/dist/core/PersistenceBuffer.js.map +1 -1
- package/dist/core/PersistenceRestore.d.ts +1 -1
- package/dist/core/PersistenceRestore.d.ts.map +1 -1
- package/dist/core/PersistenceRestore.js +4 -10
- package/dist/core/PersistenceRestore.js.map +1 -1
- package/dist/core/PersistenceWriter.d.ts.map +1 -1
- package/dist/core/PersistenceWriter.js +3 -12
- package/dist/core/PersistenceWriter.js.map +1 -1
- package/dist/core/SessionErrors.d.ts +0 -11
- package/dist/core/SessionErrors.d.ts.map +1 -1
- package/dist/core/SessionErrors.js +1 -14
- package/dist/core/SessionErrors.js.map +1 -1
- package/dist/core/SessionLock.d.ts +4 -5
- package/dist/core/SessionLock.d.ts.map +1 -1
- package/dist/core/SessionLock.js +5 -10
- package/dist/core/SessionLock.js.map +1 -1
- package/dist/core/SessionManager.d.ts +0 -2
- package/dist/core/SessionManager.d.ts.map +1 -1
- package/dist/core/SessionManager.js +3 -5
- package/dist/core/SessionManager.js.map +1 -1
- package/dist/core/SessionResetCoordinator.d.ts +10 -7
- package/dist/core/SessionResetCoordinator.d.ts.map +1 -1
- package/dist/core/SessionResetCoordinator.js +10 -28
- package/dist/core/SessionResetCoordinator.js.map +1 -1
- package/dist/core/ThoughtEvaluator.d.ts +5 -5
- package/dist/core/ThoughtEvaluator.d.ts.map +1 -1
- package/dist/core/ThoughtEvaluator.js +4 -40
- package/dist/core/ThoughtEvaluator.js.map +1 -1
- package/dist/core/ThoughtFormatter.js.map +1 -1
- package/dist/core/ThoughtProcessor.d.ts +10 -3
- package/dist/core/ThoughtProcessor.d.ts.map +1 -1
- package/dist/core/ThoughtProcessor.js +34 -38
- package/dist/core/ThoughtProcessor.js.map +1 -1
- package/dist/core/VerificationOutcomeAdmission.d.ts.map +1 -1
- package/dist/core/VerificationOutcomeAdmission.js +5 -7
- package/dist/core/VerificationOutcomeAdmission.js.map +1 -1
- package/dist/core/compression/CompressionService.d.ts +2 -1
- package/dist/core/compression/CompressionService.d.ts.map +1 -1
- package/dist/core/compression/CompressionService.js.map +1 -1
- package/dist/core/compression/DehydrationPolicy.d.ts.map +1 -1
- package/dist/core/compression/DehydrationPolicy.js.map +1 -1
- package/dist/core/compression/InMemorySummaryStore.d.ts +2 -1
- package/dist/core/compression/InMemorySummaryStore.d.ts.map +1 -1
- package/dist/core/compression/InMemorySummaryStore.js.map +1 -1
- package/dist/core/evaluator/Calibrator.d.ts +2 -2
- package/dist/core/evaluator/Calibrator.d.ts.map +1 -1
- package/dist/core/evaluator/Calibrator.js +2 -5
- package/dist/core/evaluator/Calibrator.js.map +1 -1
- package/dist/core/evaluator/SignalComputer.d.ts +2 -1
- package/dist/core/evaluator/SignalComputer.d.ts.map +1 -1
- package/dist/core/evaluator/SignalComputer.js.map +1 -1
- package/dist/core/evaluator/internals.d.ts +1 -5
- package/dist/core/evaluator/internals.d.ts.map +1 -1
- package/dist/core/evaluator/internals.js +1 -3
- package/dist/core/evaluator/internals.js.map +1 -1
- package/dist/core/graph/Edge.d.ts +1 -1
- package/dist/core/graph/EdgeEmitter.d.ts +2 -4
- package/dist/core/graph/EdgeEmitter.d.ts.map +1 -1
- package/dist/core/graph/EdgeEmitter.js +2 -4
- package/dist/core/graph/EdgeEmitter.js.map +1 -1
- package/dist/core/graph/GraphView.d.ts +13 -1
- package/dist/core/graph/GraphView.d.ts.map +1 -1
- package/dist/core/graph/GraphView.js +34 -0
- package/dist/core/graph/GraphView.js.map +1 -1
- package/dist/core/reasoning/OutcomeRecorder.d.ts +0 -1
- package/dist/core/reasoning/OutcomeRecorder.d.ts.map +1 -1
- package/dist/core/reasoning/OutcomeRecorder.js.map +1 -1
- package/dist/core/reasoning/strategies/SequentialStrategy.d.ts +3 -3
- package/dist/core/reasoning/strategies/SequentialStrategy.js.map +1 -1
- package/dist/core/reasoning/strategies/TreeOfThoughtStrategy.d.ts +6 -6
- package/dist/core/reasoning/strategies/TreeOfThoughtStrategy.d.ts.map +1 -1
- package/dist/core/reasoning/strategies/TreeOfThoughtStrategy.js +16 -2
- package/dist/core/reasoning/strategies/TreeOfThoughtStrategy.js.map +1 -1
- package/dist/core/reasoning/strategies/totScoring.d.ts.map +1 -1
- package/dist/core/reasoning/strategies/totScoring.js.map +1 -1
- package/dist/core/reasoning.d.ts +1 -3
- package/dist/core/reasoning.d.ts.map +1 -1
- package/dist/core/thought.d.ts +3 -2
- package/dist/core/thought.d.ts.map +1 -1
- package/dist/errors.d.ts +4 -20
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +2 -28
- package/dist/errors.js.map +1 -1
- package/dist/lib.d.ts +31 -24
- package/dist/lib.d.ts.map +1 -1
- package/dist/lib.js +55 -10
- package/dist/lib.js.map +1 -1
- package/dist/logger/NullLogger.d.ts +9 -11
- package/dist/logger/NullLogger.d.ts.map +1 -1
- package/dist/logger/NullLogger.js.map +1 -1
- package/dist/persistence/FilePersistence.d.ts +3 -12
- package/dist/persistence/FilePersistence.d.ts.map +1 -1
- package/dist/persistence/FilePersistence.js +9 -61
- package/dist/persistence/FilePersistence.js.map +1 -1
- package/dist/persistence/FileSnapshotV2.d.ts +2 -2
- package/dist/persistence/FileSnapshotV2.js +2 -2
- package/dist/persistence/FileSnapshotV2.js.map +1 -1
- package/dist/persistence/FileWriter.d.ts +1 -0
- package/dist/persistence/FileWriter.d.ts.map +1 -1
- package/dist/persistence/FileWriter.js +3 -3
- package/dist/persistence/FileWriter.js.map +1 -1
- package/dist/persistence/MemoryPersistence.d.ts +5 -15
- package/dist/persistence/MemoryPersistence.d.ts.map +1 -1
- package/dist/persistence/MemoryPersistence.js +6 -40
- package/dist/persistence/MemoryPersistence.js.map +1 -1
- package/dist/persistence/PersistenceCodec.js +1 -3
- package/dist/persistence/PersistenceCodec.js.map +1 -1
- package/dist/persistence/PersistenceErrors.d.ts +0 -6
- package/dist/persistence/PersistenceErrors.d.ts.map +1 -1
- package/dist/persistence/PersistenceErrors.js +1 -9
- package/dist/persistence/PersistenceErrors.js.map +1 -1
- package/dist/persistence/PersistenceScope.d.ts.map +1 -1
- package/dist/persistence/PersistenceScope.js +2 -2
- package/dist/persistence/PersistenceScope.js.map +1 -1
- package/dist/persistence/SqlitePersistence.d.ts +3 -10
- package/dist/persistence/SqlitePersistence.d.ts.map +1 -1
- package/dist/persistence/SqlitePersistence.js +2 -26
- package/dist/persistence/SqlitePersistence.js.map +1 -1
- package/dist/persistence/SqliteSchemaV2.d.ts.map +1 -1
- package/dist/persistence/SqliteSchemaV2.js +3 -12
- package/dist/persistence/SqliteSchemaV2.js.map +1 -1
- package/dist/pool/ConnectionPool.d.ts +3 -12
- package/dist/pool/ConnectionPool.d.ts.map +1 -1
- package/dist/pool/ConnectionPool.js +5 -8
- package/dist/pool/ConnectionPool.js.map +1 -1
- package/dist/pool/IConnectionPool.d.ts +3 -9
- package/dist/pool/IConnectionPool.d.ts.map +1 -1
- package/dist/registry/SkillRegistry.d.ts +1 -7
- package/dist/registry/SkillRegistry.d.ts.map +1 -1
- package/dist/registry/SkillRegistry.js +0 -15
- package/dist/registry/SkillRegistry.js.map +1 -1
- package/dist/registry/ToolRegistry.d.ts +1 -9
- package/dist/registry/ToolRegistry.d.ts.map +1 -1
- package/dist/registry/ToolRegistry.js +0 -21
- package/dist/registry/ToolRegistry.js.map +1 -1
- package/dist/schema.d.ts +2 -1
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +3 -3
- package/dist/schema.js.map +1 -1
- package/dist/transport/BaseTransport.d.ts +0 -9
- package/dist/transport/BaseTransport.d.ts.map +1 -1
- package/dist/transport/BaseTransport.js +0 -11
- package/dist/transport/BaseTransport.js.map +1 -1
- package/dist/transport/HttpHelpers.d.ts +4 -1
- package/dist/transport/HttpHelpers.d.ts.map +1 -1
- package/dist/transport/HttpHelpers.js +61 -11
- package/dist/transport/HttpHelpers.js.map +1 -1
- package/dist/transport/HttpRequestLifecycle.d.ts +15 -1
- package/dist/transport/HttpRequestLifecycle.d.ts.map +1 -1
- package/dist/transport/HttpRequestLifecycle.js +66 -4
- package/dist/transport/HttpRequestLifecycle.js.map +1 -1
- package/dist/transport/HttpTransport.d.ts +2 -0
- package/dist/transport/HttpTransport.d.ts.map +1 -1
- package/dist/transport/HttpTransport.js +75 -38
- package/dist/transport/HttpTransport.js.map +1 -1
- package/dist/transport/StreamableHttpTransport.d.ts +5 -29
- package/dist/transport/StreamableHttpTransport.d.ts.map +1 -1
- package/dist/transport/StreamableHttpTransport.js +74 -116
- package/dist/transport/StreamableHttpTransport.js.map +1 -1
- package/dist/watchers/SkillWatcher.d.ts.map +1 -1
- package/dist/watchers/SkillWatcher.js +1 -1
- package/dist/watchers/SkillWatcher.js.map +1 -1
- package/package.json +2 -2
- package/dist/contracts/PersistenceBackend.js.map +0 -1
- package/dist/persistence/FileLegacyImport.d.ts +0 -2
- package/dist/persistence/FileLegacyImport.d.ts.map +0 -1
- package/dist/persistence/FileLegacyImport.js +0 -183
- package/dist/persistence/FileLegacyImport.js.map +0 -1
- package/dist/persistence/SessionScopedPersistence.d.ts +0 -4
- package/dist/persistence/SessionScopedPersistence.d.ts.map +0 -1
- package/dist/persistence/SessionScopedPersistence.js +0 -9
- package/dist/persistence/SessionScopedPersistence.js.map +0 -1
- package/dist/persistence/SqliteLegacyImport.d.ts +0 -14
- package/dist/persistence/SqliteLegacyImport.d.ts.map +0 -1
- package/dist/persistence/SqliteLegacyImport.js +0 -136
- package/dist/persistence/SqliteLegacyImport.js.map +0 -1
- package/dist/persistence/SqliteLegacySchema.d.ts +0 -15
- package/dist/persistence/SqliteLegacySchema.d.ts.map +0 -1
- package/dist/persistence/SqliteLegacySchema.js +0 -72
- package/dist/persistence/SqliteLegacySchema.js.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import * as __rspack_external_valibot from "valibot";
|
|
3
3
|
import * as __rspack_external_node_crypto_2e7c4b46 from "node:crypto";
|
|
4
4
|
import * as __rspack_external_node_http_e245b239 from "node:http";
|
|
5
|
+
import * as __rspack_external_node_string_decoder_69b9bd04 from "node:string_decoder";
|
|
5
6
|
import * as __rspack_external_node_async_hooks_4d8b1b4a from "node:async_hooks";
|
|
6
7
|
import * as __rspack_external__tmcp_adapter_valibot_0faddfa6 from "@tmcp/adapter-valibot";
|
|
7
8
|
import * as __rspack_external__tmcp_transport_stdio_98e5584f from "@tmcp/transport-stdio";
|
|
@@ -132,13 +133,9 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
132
133
|
PERSISTENCE_DRAIN: 'PERSISTENCE_DRAIN',
|
|
133
134
|
PERSISTENCE_SESSION_ADMISSION_CLOSED: 'PERSISTENCE_SESSION_ADMISSION_CLOSED',
|
|
134
135
|
PERSISTENCE_SESSION_BARRIER_REENTRANCY: 'PERSISTENCE_SESSION_BARRIER_REENTRANCY',
|
|
135
|
-
ASYNC_RESET_REQUIRED: 'ASYNC_RESET_REQUIRED',
|
|
136
|
-
PERSISTENCE_CAPABILITY_UNSUPPORTED: 'PERSISTENCE_CAPABILITY_UNSUPPORTED',
|
|
137
136
|
PERSISTENCE_SCOPE_MISMATCH: 'PERSISTENCE_SCOPE_MISMATCH',
|
|
138
137
|
PERSISTENCE_UNAVAILABLE: 'PERSISTENCE_UNAVAILABLE',
|
|
139
|
-
PERSISTENCE_COMPATIBILITY: 'PERSISTENCE_COMPATIBILITY'
|
|
140
|
-
PERSISTENCE_IMPORT_REQUIRED: 'PERSISTENCE_IMPORT_REQUIRED',
|
|
141
|
-
PERSISTENCE_LEGACY_AMBIGUITY: 'PERSISTENCE_LEGACY_AMBIGUITY'
|
|
138
|
+
PERSISTENCE_COMPATIBILITY: 'PERSISTENCE_COMPATIBILITY'
|
|
142
139
|
};
|
|
143
140
|
/**
|
|
144
141
|
* All known warning codes as a const object.
|
|
@@ -209,7 +206,7 @@ class ConfigurationError extends SequentialThinkingError {
|
|
|
209
206
|
*
|
|
210
207
|
* @example
|
|
211
208
|
* ```typescript
|
|
212
|
-
* const tool = registry.
|
|
209
|
+
* const tool = registry.get('non-existent-tool');
|
|
213
210
|
* if (!tool) {
|
|
214
211
|
* throw new ToolNotFoundError('non-existent-tool');
|
|
215
212
|
* }
|
|
@@ -244,7 +241,7 @@ class ConfigurationError extends SequentialThinkingError {
|
|
|
244
241
|
*
|
|
245
242
|
* @example
|
|
246
243
|
* ```typescript
|
|
247
|
-
* const skill = registry.
|
|
244
|
+
* const skill = registry.get('non-existent-skill');
|
|
248
245
|
* if (!skill) {
|
|
249
246
|
* throw new SkillNotFoundError('non-existent-skill');
|
|
250
247
|
* }
|
|
@@ -380,7 +377,7 @@ class ConfigurationError extends SequentialThinkingError {
|
|
|
380
377
|
*
|
|
381
378
|
* @example
|
|
382
379
|
* ```typescript
|
|
383
|
-
* if (registry.
|
|
380
|
+
* if (registry.has(skill.name)) {
|
|
384
381
|
* throw new DuplicateSkillError(skill.name);
|
|
385
382
|
* }
|
|
386
383
|
* ```
|
|
@@ -438,7 +435,7 @@ class ConfigurationError extends SequentialThinkingError {
|
|
|
438
435
|
*
|
|
439
436
|
* @example
|
|
440
437
|
* ```typescript
|
|
441
|
-
* if (registry.
|
|
438
|
+
* if (registry.has(tool.name)) {
|
|
442
439
|
* throw new DuplicateToolError(tool.name);
|
|
443
440
|
* }
|
|
444
441
|
* ```
|
|
@@ -752,28 +749,6 @@ class PersistenceClosedError extends SequentialThinkingError {
|
|
|
752
749
|
this.cause = cause;
|
|
753
750
|
}
|
|
754
751
|
}
|
|
755
|
-
/** Error raised when legacy files require an explicit one-way import. */ class PersistenceImportRequiredError extends SequentialThinkingError {
|
|
756
|
-
sourcePath;
|
|
757
|
-
legacyArtifacts;
|
|
758
|
-
constructor(sourcePath, legacyArtifacts){
|
|
759
|
-
super(`Legacy persistence at '${sourcePath}' requires explicit import`, ERROR_CODES.PERSISTENCE_IMPORT_REQUIRED);
|
|
760
|
-
this.name = 'PersistenceImportRequiredError';
|
|
761
|
-
this.sourcePath = sourcePath;
|
|
762
|
-
this.legacyArtifacts = [
|
|
763
|
-
...legacyArtifacts
|
|
764
|
-
];
|
|
765
|
-
}
|
|
766
|
-
}
|
|
767
|
-
/** Error raised when legacy bytes do not identify one durable namespace. */ class PersistenceLegacyAmbiguityError extends SequentialThinkingError {
|
|
768
|
-
sourcePath;
|
|
769
|
-
detail;
|
|
770
|
-
constructor(sourcePath, detail){
|
|
771
|
-
super(`Legacy persistence at '${sourcePath}' is ambiguous: ${detail}`, ERROR_CODES.PERSISTENCE_LEGACY_AMBIGUITY);
|
|
772
|
-
this.name = 'PersistenceLegacyAmbiguityError';
|
|
773
|
-
this.sourcePath = sourcePath;
|
|
774
|
-
this.detail = detail;
|
|
775
|
-
}
|
|
776
|
-
}
|
|
777
752
|
/**
|
|
778
753
|
* Type guard to check if an error has a specific error code.
|
|
779
754
|
*/ function isErrorCode(err, code) {
|
|
@@ -920,8 +895,8 @@ Reasoning Enhancement Parameters:
|
|
|
920
895
|
- merge_branch_ids: Branch IDs merged into current context
|
|
921
896
|
- meta_observation: Observation about reasoning process (with thought_type 'meta')
|
|
922
897
|
- reasoning_depth: How deep to reason: 'shallow' (quick), 'moderate' (default), 'deep' (thorough)
|
|
923
|
-
- session_id:
|
|
924
|
-
- reset_state: (Optional) When true, clears all state for the
|
|
898
|
+
- session_id: Required unique identifier that scopes thought history, branches, and statistics to an explicit session. Format: alphanumeric, hyphens, underscores, 1-100 chars; the retired value __global__ is rejected.
|
|
899
|
+
- reset_state: (Optional) When true, clears all state for the required session_id before processing the current thought. Use this to start a fresh reasoning chain without accumulated state from previous chains.
|
|
925
900
|
|
|
926
901
|
Response Enrichment:
|
|
927
902
|
- When reasoning fields are set, response includes confidence_signals (depth, revision/branch count, type distribution, avg confidence, structural_quality, quality_components) and reasoning_stats (hypothesis tracking)
|
|
@@ -1170,6 +1145,7 @@ You should:
|
|
|
1170
1145
|
* thought: 'I need to analyze the problem',
|
|
1171
1146
|
* thought_number: 1,
|
|
1172
1147
|
* total_thoughts: 5,
|
|
1148
|
+
* session_id: 'analysis-task',
|
|
1173
1149
|
* next_thought_needed: true,
|
|
1174
1150
|
* available_mcp_tools: ['Read', 'Write', 'Grep']
|
|
1175
1151
|
* });
|
|
@@ -1226,7 +1202,7 @@ You should:
|
|
|
1226
1202
|
'moderate',
|
|
1227
1203
|
'deep'
|
|
1228
1204
|
]), valibot__rspack_import_0.description('Effort signal: how deep reasoning should go'))),
|
|
1229
|
-
session_id: valibot__rspack_import_0.
|
|
1205
|
+
session_id: valibot__rspack_import_0.pipe(valibot__rspack_import_0.string(), valibot__rspack_import_0.regex(/^[a-zA-Z0-9_-]+$/, 'Session ID must contain only letters, numbers, hyphens, and underscores'), valibot__rspack_import_0.minLength(1), valibot__rspack_import_0.maxLength(100), valibot__rspack_import_0.notValue('__global__', "Session ID '__global__' is retired; use an explicit named session"), valibot__rspack_import_0.description('Required session identifier for state isolation. Thought history, branches, and statistics are scoped to this explicit named session.')),
|
|
1230
1206
|
reset_state: valibot__rspack_import_0.optional(valibot__rspack_import_0.pipe(valibot__rspack_import_0.boolean(), valibot__rspack_import_0.description('When true, clears all state for the target session before processing this thought. The thought is then processed as the first in a fresh session.'))),
|
|
1231
1207
|
tool_name: valibot__rspack_import_0.optional(valibot__rspack_import_0.pipe(valibot__rspack_import_0.string(), valibot__rspack_import_0.minLength(1), valibot__rspack_import_0.description('Name of the tool being invoked (for tool_call thoughts)'))),
|
|
1232
1208
|
tool_arguments: valibot__rspack_import_0.optional(valibot__rspack_import_0.pipe(valibot__rspack_import_0.record(valibot__rspack_import_0.string(), valibot__rspack_import_0.unknown()), valibot__rspack_import_0.description('Arguments passed to the tool (for tool_call thoughts)'))),
|
|
@@ -1326,7 +1302,7 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
1326
1302
|
|
|
1327
1303
|
|
|
1328
1304
|
},
|
|
1329
|
-
"
|
|
1305
|
+
"q"(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
1330
1306
|
|
|
1331
1307
|
// EXPORTS
|
|
1332
1308
|
__webpack_require__.d(__webpack_exports__, {
|
|
@@ -1390,7 +1366,6 @@ var schema = __webpack_require__("R");
|
|
|
1390
1366
|
* @remarks
|
|
1391
1367
|
* **Security Features:**
|
|
1392
1368
|
* - Session ID validation (alphanumeric, max 64 chars)
|
|
1393
|
-
* - Query parameter sanitization (whitelist allowed keys)
|
|
1394
1369
|
* - Rate limiting per IP (configurable, default 100 req/min)
|
|
1395
1370
|
* - CORS origin validation
|
|
1396
1371
|
*
|
|
@@ -1414,14 +1389,6 @@ var schema = __webpack_require__("R");
|
|
|
1414
1389
|
return this._level;
|
|
1415
1390
|
}
|
|
1416
1391
|
}
|
|
1417
|
-
/**
|
|
1418
|
-
* Allowed query parameter names (whitelist for security).
|
|
1419
|
-
*/ const ALLOWED_QUERY_PARAMS = new Set([
|
|
1420
|
-
'session',
|
|
1421
|
-
'sessionId',
|
|
1422
|
-
'client',
|
|
1423
|
-
'clientId'
|
|
1424
|
-
]);
|
|
1425
1392
|
/**
|
|
1426
1393
|
* Rate limit settings (requests per minute per IP).
|
|
1427
1394
|
*/ const RATE_LIMIT_REQUESTS = 100;
|
|
@@ -1473,20 +1440,6 @@ class BaseTransport {
|
|
|
1473
1440
|
}
|
|
1474
1441
|
return SESSION_ID_PATTERN.test(sessionId);
|
|
1475
1442
|
}
|
|
1476
|
-
/**
|
|
1477
|
-
* Sanitize query parameters by removing any not in whitelist.
|
|
1478
|
-
*
|
|
1479
|
-
* @param url - The URL object containing query parameters
|
|
1480
|
-
* @returns A sanitized record of allowed query parameters
|
|
1481
|
-
*/ sanitizeQueryParams(url) {
|
|
1482
|
-
const sanitized = {};
|
|
1483
|
-
for (const [key, value] of url.searchParams.entries()){
|
|
1484
|
-
if (ALLOWED_QUERY_PARAMS.has(key)) {
|
|
1485
|
-
sanitized[key] = value;
|
|
1486
|
-
}
|
|
1487
|
-
}
|
|
1488
|
-
return sanitized;
|
|
1489
|
-
}
|
|
1490
1443
|
/**
|
|
1491
1444
|
* Check rate limit for a given IP address.
|
|
1492
1445
|
*
|
|
@@ -1725,13 +1678,12 @@ class BaseTransport {
|
|
|
1725
1678
|
* Validate and brand a string as a {@link SessionId}.
|
|
1726
1679
|
*
|
|
1727
1680
|
* Enforces {@link SESSION_ID_PATTERN} and {@link MAX_SESSION_ID_LENGTH}.
|
|
1728
|
-
* The
|
|
1681
|
+
* The retired global session sentinel `__global__` is rejected.
|
|
1729
1682
|
*
|
|
1730
1683
|
* @throws {ValidationError} when the input is not a valid session id.
|
|
1731
1684
|
*/ function asSessionId(value) {
|
|
1732
1685
|
if (value === '__global__') {
|
|
1733
|
-
|
|
1734
|
-
return value;
|
|
1686
|
+
throw new errors/* .ValidationError */.yI('session_id', "reserved value '__global__' is retired; use an explicit named session");
|
|
1735
1687
|
}
|
|
1736
1688
|
if (typeof value !== 'string' || value.length === 0) {
|
|
1737
1689
|
throw new errors/* .ValidationError */.yI('session_id', 'must be a non-empty string');
|
|
@@ -1772,12 +1724,8 @@ class BaseTransport {
|
|
|
1772
1724
|
/** Generate a fresh {@link SummaryId}. */ function generateSummaryId() {
|
|
1773
1725
|
return generateUlid();
|
|
1774
1726
|
}
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
*
|
|
1778
|
-
* Branded once here so production and test code share one constant
|
|
1779
|
-
* instead of casting `'__global__'` ad-hoc.
|
|
1780
|
-
*/ const GLOBAL_SESSION_ID = asSessionId('__global__');
|
|
1727
|
+
|
|
1728
|
+
;// CONCATENATED MODULE: external "node:string_decoder"
|
|
1781
1729
|
|
|
1782
1730
|
;// CONCATENATED MODULE: ./src/transport/HttpHelpers.ts
|
|
1783
1731
|
/**
|
|
@@ -1788,7 +1736,11 @@ class BaseTransport {
|
|
|
1788
1736
|
* HttpTransport and StreamableHttpTransport.
|
|
1789
1737
|
*
|
|
1790
1738
|
* @module transport/HttpHelpers
|
|
1791
|
-
*/
|
|
1739
|
+
*/
|
|
1740
|
+
class RequestBodyAbortedError extends Error {
|
|
1741
|
+
name = 'RequestBodyAbortedError';
|
|
1742
|
+
}
|
|
1743
|
+
/**
|
|
1792
1744
|
* Send a JSON-RPC 2.0 error response.
|
|
1793
1745
|
*
|
|
1794
1746
|
* Standardizes error response formatting across all transport implementations.
|
|
@@ -1856,23 +1808,118 @@ class BaseTransport {
|
|
|
1856
1808
|
* @param req - The incoming HTTP request
|
|
1857
1809
|
* @param maxBodySize - Maximum allowed body size in bytes (0 = unlimited)
|
|
1858
1810
|
* @returns The body string, or `null` if the body exceeded the size limit
|
|
1859
|
-
*/ async function readRequestBody(req, maxBodySize) {
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1811
|
+
*/ async function readRequestBody(req, maxBodySize, signal) {
|
|
1812
|
+
return new Promise((resolve, reject)=>{
|
|
1813
|
+
let body = '';
|
|
1814
|
+
let bodySize = 0;
|
|
1815
|
+
let settled = false;
|
|
1816
|
+
const decoder = new __rspack_external_node_string_decoder_69b9bd04.StringDecoder('utf8');
|
|
1817
|
+
const cleanup = ()=>{
|
|
1818
|
+
req.off('data', onData);
|
|
1819
|
+
req.off('end', onEnd);
|
|
1820
|
+
req.off('aborted', onAborted);
|
|
1821
|
+
req.off('close', onAborted);
|
|
1822
|
+
req.off('error', onError);
|
|
1823
|
+
signal?.removeEventListener('abort', onAborted);
|
|
1824
|
+
};
|
|
1825
|
+
const onData = (chunk)=>{
|
|
1826
|
+
if (settled) return;
|
|
1827
|
+
const chunkSize = typeof chunk === 'string' ? Buffer.byteLength(chunk) : chunk.byteLength;
|
|
1828
|
+
bodySize += chunkSize;
|
|
1829
|
+
if (maxBodySize > 0 && bodySize > maxBodySize) {
|
|
1830
|
+
settled = true;
|
|
1831
|
+
cleanup();
|
|
1832
|
+
req.resume();
|
|
1833
|
+
resolve(null);
|
|
1834
|
+
return;
|
|
1835
|
+
}
|
|
1836
|
+
body += typeof chunk === 'string' ? chunk : decoder.write(chunk);
|
|
1837
|
+
};
|
|
1838
|
+
const onEnd = ()=>{
|
|
1839
|
+
if (settled) return;
|
|
1840
|
+
settled = true;
|
|
1841
|
+
cleanup();
|
|
1842
|
+
resolve(body + decoder.end());
|
|
1843
|
+
};
|
|
1844
|
+
const onAborted = ()=>{
|
|
1845
|
+
if (settled) return;
|
|
1846
|
+
settled = true;
|
|
1847
|
+
cleanup();
|
|
1848
|
+
req.resume();
|
|
1849
|
+
reject(new RequestBodyAbortedError());
|
|
1850
|
+
};
|
|
1851
|
+
const onError = (error)=>{
|
|
1852
|
+
if (settled) return;
|
|
1853
|
+
settled = true;
|
|
1854
|
+
cleanup();
|
|
1855
|
+
reject(error);
|
|
1856
|
+
};
|
|
1857
|
+
req.on('data', onData);
|
|
1858
|
+
req.once('end', onEnd);
|
|
1859
|
+
req.once('aborted', onAborted);
|
|
1860
|
+
req.once('close', onAborted);
|
|
1861
|
+
req.once('error', onError);
|
|
1862
|
+
signal?.addEventListener('abort', onAborted, {
|
|
1863
|
+
once: true
|
|
1864
|
+
});
|
|
1865
|
+
if (signal?.aborted) onAborted();
|
|
1866
|
+
});
|
|
1871
1867
|
}
|
|
1872
1868
|
|
|
1873
1869
|
// EXTERNAL MODULE: ./src/context/RequestContext.ts + 1 modules
|
|
1874
1870
|
var RequestContext = __webpack_require__("i");
|
|
1875
1871
|
;// CONCATENATED MODULE: ./src/transport/HttpRequestLifecycle.ts
|
|
1872
|
+
class TrackedPreDispatchLease {
|
|
1873
|
+
_onRelease;
|
|
1874
|
+
_controller = new AbortController();
|
|
1875
|
+
_settled = Promise.withResolvers();
|
|
1876
|
+
_active = true;
|
|
1877
|
+
_cancellationReason = null;
|
|
1878
|
+
constructor(_onRelease){
|
|
1879
|
+
this._onRelease = _onRelease;
|
|
1880
|
+
}
|
|
1881
|
+
get signal() {
|
|
1882
|
+
return this._controller.signal;
|
|
1883
|
+
}
|
|
1884
|
+
get cancellationReason() {
|
|
1885
|
+
return this._cancellationReason;
|
|
1886
|
+
}
|
|
1887
|
+
get settled() {
|
|
1888
|
+
return this._settled.promise;
|
|
1889
|
+
}
|
|
1890
|
+
cancel(reason) {
|
|
1891
|
+
if (!this._active || this._controller.signal.aborted) return;
|
|
1892
|
+
this._cancellationReason = reason;
|
|
1893
|
+
this._controller.abort();
|
|
1894
|
+
}
|
|
1895
|
+
release() {
|
|
1896
|
+
if (!this._active) return;
|
|
1897
|
+
this._active = false;
|
|
1898
|
+
this._onRelease(this);
|
|
1899
|
+
this._settled.resolve();
|
|
1900
|
+
}
|
|
1901
|
+
}
|
|
1902
|
+
class PreDispatchTracker {
|
|
1903
|
+
_leases = new Set();
|
|
1904
|
+
_accepting = true;
|
|
1905
|
+
acquire() {
|
|
1906
|
+
if (!this._accepting) return null;
|
|
1907
|
+
const lease = new TrackedPreDispatchLease((released)=>this._leases.delete(released));
|
|
1908
|
+
this._leases.add(lease);
|
|
1909
|
+
return lease;
|
|
1910
|
+
}
|
|
1911
|
+
closeAdmission(reason) {
|
|
1912
|
+
this._accepting = false;
|
|
1913
|
+
for (const lease of this._leases)lease.cancel(reason);
|
|
1914
|
+
}
|
|
1915
|
+
async join() {
|
|
1916
|
+
while(this._leases.size > 0){
|
|
1917
|
+
await Promise.all([
|
|
1918
|
+
...this._leases
|
|
1919
|
+
].map((lease)=>lease.settled));
|
|
1920
|
+
}
|
|
1921
|
+
}
|
|
1922
|
+
}
|
|
1876
1923
|
/** Maximum number of reporting failures retained for diagnostics. */ const LIFECYCLE_REPORTING_FAILURE_CAPACITY = 32;
|
|
1877
1924
|
class LifecycleFailureReporter {
|
|
1878
1925
|
_onFailure;
|
|
@@ -1944,14 +1991,27 @@ class AcceptedWorkTracker {
|
|
|
1944
1991
|
get size() {
|
|
1945
1992
|
return this._work.size;
|
|
1946
1993
|
}
|
|
1947
|
-
|
|
1994
|
+
transfer(lease, start) {
|
|
1995
|
+
lease.signal.throwIfAborted();
|
|
1996
|
+
const reservation = Promise.withResolvers();
|
|
1997
|
+
this._work.add(reservation.promise);
|
|
1998
|
+
lease.release();
|
|
1999
|
+
let work;
|
|
2000
|
+
try {
|
|
2001
|
+
work = start();
|
|
2002
|
+
} catch (error) {
|
|
2003
|
+
this._work.delete(reservation.promise);
|
|
2004
|
+
reservation.resolve();
|
|
2005
|
+
throw error;
|
|
2006
|
+
}
|
|
1948
2007
|
const observed = work.catch((error)=>{
|
|
1949
2008
|
this._failureReporter.report(error);
|
|
1950
2009
|
});
|
|
1951
|
-
this._work.add(observed);
|
|
1952
2010
|
void observed.then(()=>{
|
|
1953
|
-
this._work.delete(
|
|
2011
|
+
this._work.delete(reservation.promise);
|
|
2012
|
+
reservation.resolve();
|
|
1954
2013
|
});
|
|
2014
|
+
return work;
|
|
1955
2015
|
}
|
|
1956
2016
|
async join() {
|
|
1957
2017
|
while(this._work.size > 0){
|
|
@@ -1964,12 +2024,8 @@ class AcceptedWorkTracker {
|
|
|
1964
2024
|
/**
|
|
1965
2025
|
* Streamable HTTP Transport implementation (MCP spec recommended transport).
|
|
1966
2026
|
*
|
|
1967
|
-
* This transport implements the MCP Streamable HTTP specification, which replaces
|
|
1968
|
-
* the deprecated SSE transport as the recommended HTTP-based transport since March 2025.
|
|
1969
|
-
*
|
|
1970
2027
|
* Key features:
|
|
1971
2028
|
* - POST /mcp for JSON-RPC requests (main MCP endpoint)
|
|
1972
|
-
* - GET /mcp for optional SSE server-to-client notifications
|
|
1973
2029
|
* - Session management via Mcp-Session-Id header
|
|
1974
2030
|
* - Supports both stateful (session-based) and stateless (per-request) modes
|
|
1975
2031
|
* - Health endpoints (/health, /ready)
|
|
@@ -2011,8 +2067,7 @@ function parseSessionRetentionOptions(options) {
|
|
|
2011
2067
|
* Streamable HTTP Transport for MCP server.
|
|
2012
2068
|
*
|
|
2013
2069
|
* This transport implements the MCP Streamable HTTP specification,
|
|
2014
|
-
* providing JSON-RPC over HTTP with optional session management
|
|
2015
|
-
* and server-to-client SSE notification streams.
|
|
2070
|
+
* providing JSON-RPC over HTTP with optional session management.
|
|
2016
2071
|
*
|
|
2017
2072
|
* @remarks
|
|
2018
2073
|
* **Security Features (inherited from BaseTransport):**
|
|
@@ -2024,13 +2079,11 @@ function parseSessionRetentionOptions(options) {
|
|
|
2024
2079
|
*
|
|
2025
2080
|
* **MCP Streamable HTTP Spec Compliance:**
|
|
2026
2081
|
* - POST /mcp — JSON-RPC method calls
|
|
2027
|
-
* - GET /mcp — SSE notification stream (server-to-client)
|
|
2028
2082
|
* - Mcp-Session-Id header for session management
|
|
2029
2083
|
* - Content-Type: application/json for JSON-RPC responses
|
|
2030
|
-
* - Content-Type: text/event-stream for SSE notification streams
|
|
2031
2084
|
*
|
|
2032
2085
|
* **HTTP Status Code Mapping:**
|
|
2033
|
-
* - 200: Success (JSON-RPC response
|
|
2086
|
+
* - 200: Success (JSON-RPC response)
|
|
2034
2087
|
* - 202: Accepted (JSON-RPC notification, no response body)
|
|
2035
2088
|
* - 204: CORS Preflight (empty body)
|
|
2036
2089
|
* - 400: Bad Request (invalid JSON, invalid session ID)
|
|
@@ -2060,6 +2113,7 @@ function parseSessionRetentionOptions(options) {
|
|
|
2060
2113
|
_metricsProvider;
|
|
2061
2114
|
_lifecycleFailureReporter;
|
|
2062
2115
|
_acceptedWork;
|
|
2116
|
+
_preDispatch = new PreDispatchTracker();
|
|
2063
2117
|
_sessionRetention;
|
|
2064
2118
|
_sessionSweepIntervalId = null;
|
|
2065
2119
|
_stopPromise = null;
|
|
@@ -2142,15 +2196,18 @@ function parseSessionRetentionOptions(options) {
|
|
|
2142
2196
|
}
|
|
2143
2197
|
});
|
|
2144
2198
|
}
|
|
2145
|
-
|
|
2146
|
-
* Route and handle incoming HTTP requests.
|
|
2147
|
-
*/ async _handleRequest(req, res) {
|
|
2199
|
+
_recordRequestMetrics(res) {
|
|
2148
2200
|
const startTime = Date.now();
|
|
2149
2201
|
this._metrics?.counter('streamable_http_requests_total', 1, {}, 'Total Streamable HTTP transport requests');
|
|
2150
2202
|
res.once('finish', ()=>{
|
|
2151
2203
|
const durationSeconds = (Date.now() - startTime) / 1000;
|
|
2152
2204
|
this._metrics?.histogram('streamable_http_request_duration_seconds', durationSeconds, {});
|
|
2153
2205
|
});
|
|
2206
|
+
}
|
|
2207
|
+
/**
|
|
2208
|
+
* Route and handle incoming HTTP requests.
|
|
2209
|
+
*/ async _handleRequest(req, res) {
|
|
2210
|
+
this._recordRequestMetrics(res);
|
|
2154
2211
|
// Host validation
|
|
2155
2212
|
if (!this.validateHostHeader(req)) {
|
|
2156
2213
|
this._sendJsonRpcError(res, 403, -32000, 'Forbidden - invalid host header');
|
|
@@ -2201,16 +2258,20 @@ function parseSessionRetentionOptions(options) {
|
|
|
2201
2258
|
// MCP endpoint routing
|
|
2202
2259
|
if (urlPath === this._path) {
|
|
2203
2260
|
if (req.method === 'POST') {
|
|
2204
|
-
this.
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2261
|
+
const lease = this._preDispatch.acquire();
|
|
2262
|
+
if (!lease) {
|
|
2263
|
+
const responseFinalizer = new ResponseFinalizer(res, this._lifecycleFailureReporter);
|
|
2264
|
+
responseFinalizer.finalize((response)=>{
|
|
2265
|
+
this._sendJsonRpcError(response, 503, -32603, 'Server is shutting down');
|
|
2266
|
+
});
|
|
2267
|
+
return;
|
|
2268
|
+
}
|
|
2269
|
+
await this._handleMcpPost(req, res, lease);
|
|
2209
2270
|
return;
|
|
2210
2271
|
}
|
|
2211
2272
|
res.writeHead(405, {
|
|
2212
2273
|
'Content-Type': 'application/json',
|
|
2213
|
-
Allow: '
|
|
2274
|
+
Allow: 'POST'
|
|
2214
2275
|
});
|
|
2215
2276
|
res.end(JSON.stringify({
|
|
2216
2277
|
jsonrpc: '2.0',
|
|
@@ -2244,6 +2305,28 @@ function parseSessionRetentionOptions(options) {
|
|
|
2244
2305
|
error
|
|
2245
2306
|
}));
|
|
2246
2307
|
}
|
|
2308
|
+
_parseJsonRpcRequest(body, responseFinalizer) {
|
|
2309
|
+
let rawBody;
|
|
2310
|
+
try {
|
|
2311
|
+
rawBody = JSON.parse(body);
|
|
2312
|
+
} catch {
|
|
2313
|
+
responseFinalizer.finalize((response)=>{
|
|
2314
|
+
this._sendJsonRpcError(response, 200, -32700, 'Parse error');
|
|
2315
|
+
});
|
|
2316
|
+
return null;
|
|
2317
|
+
}
|
|
2318
|
+
const parseResult = (0,external_valibot_.safeParse)(schema/* .JsonRpcRequestSchema */.Uv, rawBody);
|
|
2319
|
+
const rawId = rawBody && typeof rawBody === 'object' && 'id' in rawBody ? rawBody.id ?? null : null;
|
|
2320
|
+
if (!parseResult.success) {
|
|
2321
|
+
responseFinalizer.finalize((response)=>{
|
|
2322
|
+
this._sendJsonRpcError(response, 200, -32600, 'Invalid Request', rawId, {
|
|
2323
|
+
data: parseResult.issues
|
|
2324
|
+
});
|
|
2325
|
+
});
|
|
2326
|
+
return null;
|
|
2327
|
+
}
|
|
2328
|
+
return parseResult.output;
|
|
2329
|
+
}
|
|
2247
2330
|
/**
|
|
2248
2331
|
* Handle POST /mcp — JSON-RPC method calls.
|
|
2249
2332
|
*
|
|
@@ -2252,65 +2335,67 @@ function parseSessionRetentionOptions(options) {
|
|
|
2252
2335
|
* - Returns Mcp-Session-Id header for new sessions (stateful mode)
|
|
2253
2336
|
* - Validates Mcp-Session-Id for existing sessions (stateful mode)
|
|
2254
2337
|
* - Content-Type: application/json for responses
|
|
2255
|
-
*/ async _handleMcpPost(req, res) {
|
|
2338
|
+
*/ async _handleMcpPost(req, res, lease) {
|
|
2256
2339
|
this._requestCount++;
|
|
2257
2340
|
this._activeRequests++;
|
|
2258
2341
|
const responseFinalizer = new ResponseFinalizer(res, this._lifecycleFailureReporter);
|
|
2259
2342
|
let acceptedSession = null;
|
|
2343
|
+
const onAborted = ()=>lease.cancel('peer');
|
|
2344
|
+
req.once('aborted', onAborted);
|
|
2260
2345
|
const timeout = setTimeout(()=>{
|
|
2261
2346
|
responseFinalizer.finalize((response)=>{
|
|
2262
2347
|
this._sendJsonRpcError(response, 500, -32603, 'Request timeout');
|
|
2263
2348
|
});
|
|
2349
|
+
lease.cancel('timeout');
|
|
2264
2350
|
}, this._requestTimeout);
|
|
2265
2351
|
try {
|
|
2266
2352
|
// Read request body with size limit
|
|
2267
|
-
const body = await readRequestBody(req, this._bodySizeLimitEnabled ? this._maxBodySize : 0);
|
|
2353
|
+
const body = await readRequestBody(req, this._bodySizeLimitEnabled ? this._maxBodySize : 0, lease.signal);
|
|
2268
2354
|
if (body === null) {
|
|
2269
2355
|
responseFinalizer.finalize((response)=>{
|
|
2270
2356
|
this._sendJsonRpcError(response, 413, -32000, 'Request body too large');
|
|
2271
2357
|
});
|
|
2272
2358
|
return;
|
|
2273
2359
|
}
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
try {
|
|
2277
|
-
rawBody = JSON.parse(body);
|
|
2278
|
-
} catch {
|
|
2279
|
-
responseFinalizer.finalize((response)=>{
|
|
2280
|
-
this._sendJsonRpcError(response, 200, -32700, 'Parse error');
|
|
2281
|
-
});
|
|
2282
|
-
return;
|
|
2283
|
-
}
|
|
2284
|
-
// Validate JSON-RPC schema
|
|
2285
|
-
const parseResult = (0,external_valibot_.safeParse)(schema/* .JsonRpcRequestSchema */.Uv, rawBody);
|
|
2286
|
-
const rawId = rawBody && typeof rawBody === 'object' && 'id' in rawBody ? rawBody.id ?? null : null;
|
|
2287
|
-
if (!parseResult.success) {
|
|
2288
|
-
responseFinalizer.finalize((response)=>{
|
|
2289
|
-
this._sendJsonRpcError(response, 200, -32600, 'Invalid Request', rawId, {
|
|
2290
|
-
data: parseResult.issues
|
|
2291
|
-
});
|
|
2292
|
-
});
|
|
2293
|
-
return;
|
|
2294
|
-
}
|
|
2295
|
-
const jsonRpcRequest = parseResult.output;
|
|
2360
|
+
const jsonRpcRequest = this._parseJsonRpcRequest(body, responseFinalizer);
|
|
2361
|
+
if (jsonRpcRequest === null) return;
|
|
2296
2362
|
const session = this._acceptPostSession(req, responseFinalizer);
|
|
2297
2363
|
if (!session) return;
|
|
2298
2364
|
acceptedSession = session.state;
|
|
2299
2365
|
// Check if MCP server is ready
|
|
2300
2366
|
if (!this._mcpServer) {
|
|
2367
|
+
const requestId = 'id' in jsonRpcRequest ? jsonRpcRequest.id ?? null : null;
|
|
2301
2368
|
responseFinalizer.finalize((response)=>{
|
|
2302
|
-
this._sendJsonRpcError(response, 503, -32603, 'Server not ready',
|
|
2369
|
+
this._sendJsonRpcError(response, 503, -32603, 'Server not ready', requestId);
|
|
2303
2370
|
});
|
|
2304
2371
|
return;
|
|
2305
2372
|
}
|
|
2306
|
-
|
|
2373
|
+
req.off('aborted', onAborted);
|
|
2374
|
+
const acceptedWork = this._acceptedWork.transfer(lease, ()=>this._receiveAndFinalize(jsonRpcRequest, session.id, responseFinalizer).catch((error)=>{
|
|
2375
|
+
responseFinalizer.finalize((response)=>{
|
|
2376
|
+
this._sendJsonRpcError(response, 200, -32603, 'Internal error', null, {
|
|
2377
|
+
data: (0,errors/* .getErrorMessage */.u1)(error)
|
|
2378
|
+
});
|
|
2379
|
+
});
|
|
2380
|
+
}));
|
|
2381
|
+
await acceptedWork;
|
|
2307
2382
|
} catch (error) {
|
|
2383
|
+
if (lease.signal.aborted) {
|
|
2384
|
+
if (lease.cancellationReason === 'shutdown') {
|
|
2385
|
+
responseFinalizer.finalize((response)=>{
|
|
2386
|
+
this._sendJsonRpcError(response, 503, -32603, 'Server is shutting down');
|
|
2387
|
+
});
|
|
2388
|
+
}
|
|
2389
|
+
return;
|
|
2390
|
+
}
|
|
2308
2391
|
responseFinalizer.finalize((response)=>{
|
|
2309
2392
|
this._sendJsonRpcError(response, 200, -32603, 'Internal error', null, {
|
|
2310
2393
|
data: (0,errors/* .getErrorMessage */.u1)(error)
|
|
2311
2394
|
});
|
|
2312
2395
|
});
|
|
2313
2396
|
} finally{
|
|
2397
|
+
req.off('aborted', onAborted);
|
|
2398
|
+
lease.release();
|
|
2314
2399
|
if (acceptedSession) acceptedSession.acceptedPostCount--;
|
|
2315
2400
|
clearTimeout(timeout);
|
|
2316
2401
|
this._activeRequests--;
|
|
@@ -2363,82 +2448,6 @@ function parseSessionRetentionOptions(options) {
|
|
|
2363
2448
|
httpResponse.end();
|
|
2364
2449
|
});
|
|
2365
2450
|
}
|
|
2366
|
-
/**
|
|
2367
|
-
* Handle GET /mcp — Optional SSE notification stream.
|
|
2368
|
-
*
|
|
2369
|
-
* Per the MCP Streamable HTTP spec, clients may open a GET request
|
|
2370
|
-
* to receive server-initiated notifications as SSE events.
|
|
2371
|
-
* Requires a valid Mcp-Session-Id in stateful mode.
|
|
2372
|
-
*/ _handleMcpGet(req, res) {
|
|
2373
|
-
if (!this._stateful) {
|
|
2374
|
-
// SSE notification streams require stateful mode
|
|
2375
|
-
res.writeHead(405, {
|
|
2376
|
-
'Content-Type': 'application/json',
|
|
2377
|
-
Allow: 'POST'
|
|
2378
|
-
});
|
|
2379
|
-
res.end(JSON.stringify({
|
|
2380
|
-
jsonrpc: '2.0',
|
|
2381
|
-
id: null,
|
|
2382
|
-
error: {
|
|
2383
|
-
code: -32601,
|
|
2384
|
-
message: 'GET not supported in stateless mode'
|
|
2385
|
-
}
|
|
2386
|
-
}));
|
|
2387
|
-
return;
|
|
2388
|
-
}
|
|
2389
|
-
// Require Mcp-Session-Id for GET requests
|
|
2390
|
-
const sessionId = this._getSessionIdFromHeader(req);
|
|
2391
|
-
if (!sessionId) {
|
|
2392
|
-
res.writeHead(400, {
|
|
2393
|
-
'Content-Type': 'application/json'
|
|
2394
|
-
});
|
|
2395
|
-
res.end(JSON.stringify({
|
|
2396
|
-
jsonrpc: '2.0',
|
|
2397
|
-
id: null,
|
|
2398
|
-
error: {
|
|
2399
|
-
code: -32600,
|
|
2400
|
-
message: 'Missing Mcp-Session-Id header'
|
|
2401
|
-
}
|
|
2402
|
-
}));
|
|
2403
|
-
return;
|
|
2404
|
-
}
|
|
2405
|
-
const session = this._sessions.get(asSessionId(sessionId));
|
|
2406
|
-
if (!session) {
|
|
2407
|
-
res.writeHead(404, {
|
|
2408
|
-
'Content-Type': 'application/json'
|
|
2409
|
-
});
|
|
2410
|
-
res.end(JSON.stringify({
|
|
2411
|
-
jsonrpc: '2.0',
|
|
2412
|
-
id: null,
|
|
2413
|
-
error: {
|
|
2414
|
-
code: -32001,
|
|
2415
|
-
message: 'Session not found'
|
|
2416
|
-
}
|
|
2417
|
-
}));
|
|
2418
|
-
return;
|
|
2419
|
-
}
|
|
2420
|
-
session.lastActivityAt = Date.now();
|
|
2421
|
-
// Set SSE headers
|
|
2422
|
-
res.writeHead(200, {
|
|
2423
|
-
'Content-Type': 'text/event-stream',
|
|
2424
|
-
'Cache-Control': 'no-cache',
|
|
2425
|
-
Connection: 'keep-alive',
|
|
2426
|
-
'Mcp-Session-Id': sessionId
|
|
2427
|
-
});
|
|
2428
|
-
// Send initial connected event
|
|
2429
|
-
this._sendSseEvent(res, 'connected', {
|
|
2430
|
-
sessionId,
|
|
2431
|
-
timestamp: Date.now()
|
|
2432
|
-
});
|
|
2433
|
-
// Track this notification stream
|
|
2434
|
-
session.notificationStreams.add(res);
|
|
2435
|
-
this._updateSessionMetrics();
|
|
2436
|
-
// Handle client disconnect
|
|
2437
|
-
req.on('close', ()=>{
|
|
2438
|
-
session.notificationStreams.delete(res);
|
|
2439
|
-
this._updateSessionMetrics();
|
|
2440
|
-
});
|
|
2441
|
-
}
|
|
2442
2451
|
/**
|
|
2443
2452
|
* Resolve or create a session for a stateful request.
|
|
2444
2453
|
*
|
|
@@ -2484,7 +2493,6 @@ function parseSessionRetentionOptions(options) {
|
|
|
2484
2493
|
id: newSessionId,
|
|
2485
2494
|
createdAt: now,
|
|
2486
2495
|
lastActivityAt: now,
|
|
2487
|
-
notificationStreams: new Set(),
|
|
2488
2496
|
acceptedPostCount: 0
|
|
2489
2497
|
};
|
|
2490
2498
|
this._sessions.set(newSessionId, sessionState);
|
|
@@ -2505,17 +2513,7 @@ function parseSessionRetentionOptions(options) {
|
|
|
2505
2513
|
}
|
|
2506
2514
|
}
|
|
2507
2515
|
_disposeSession(sessionId) {
|
|
2508
|
-
|
|
2509
|
-
if (!session) return;
|
|
2510
|
-
this._sessions.delete(sessionId);
|
|
2511
|
-
for (const stream of session.notificationStreams){
|
|
2512
|
-
try {
|
|
2513
|
-
stream.end();
|
|
2514
|
-
} catch (error) {
|
|
2515
|
-
this._lifecycleFailureReporter.report(error);
|
|
2516
|
-
}
|
|
2517
|
-
}
|
|
2518
|
-
session.notificationStreams.clear();
|
|
2516
|
+
if (!this._sessions.delete(sessionId)) return;
|
|
2519
2517
|
this._updateSessionMetrics();
|
|
2520
2518
|
}
|
|
2521
2519
|
_stopSessionSweep() {
|
|
@@ -2534,31 +2532,6 @@ function parseSessionRetentionOptions(options) {
|
|
|
2534
2532
|
}
|
|
2535
2533
|
return undefined;
|
|
2536
2534
|
}
|
|
2537
|
-
/**
|
|
2538
|
-
* Send an SSE event to a specific client response stream.
|
|
2539
|
-
*/ _sendSseEvent(res, event, data) {
|
|
2540
|
-
try {
|
|
2541
|
-
res.write(`event: ${event}\n`);
|
|
2542
|
-
res.write(`data: ${JSON.stringify(data)}\n\n`);
|
|
2543
|
-
} catch {
|
|
2544
|
-
// Client disconnected — ignore
|
|
2545
|
-
}
|
|
2546
|
-
}
|
|
2547
|
-
/**
|
|
2548
|
-
* Broadcast a notification to all SSE streams in a given session.
|
|
2549
|
-
*
|
|
2550
|
-
* @param sessionId - Target session ID
|
|
2551
|
-
* @param event - SSE event name
|
|
2552
|
-
* @param data - Event payload
|
|
2553
|
-
*/ broadcastToSession(sessionId, event, data) {
|
|
2554
|
-
const session = this._sessions.get(asSessionId(sessionId));
|
|
2555
|
-
if (!session) {
|
|
2556
|
-
return;
|
|
2557
|
-
}
|
|
2558
|
-
for (const stream of session.notificationStreams){
|
|
2559
|
-
this._sendSseEvent(stream, event, data);
|
|
2560
|
-
}
|
|
2561
|
-
}
|
|
2562
2535
|
/**
|
|
2563
2536
|
* Handle GET /metrics endpoint.
|
|
2564
2537
|
*/ _handleMetrics(res) {
|
|
@@ -2617,11 +2590,6 @@ function parseSessionRetentionOptions(options) {
|
|
|
2617
2590
|
* Update session-related metrics.
|
|
2618
2591
|
*/ _updateSessionMetrics() {
|
|
2619
2592
|
this._metrics?.gauge('streamable_http_active_sessions', this._sessions.size, {}, 'Active Streamable HTTP sessions');
|
|
2620
|
-
let totalStreams = 0;
|
|
2621
|
-
for (const session of this._sessions.values()){
|
|
2622
|
-
totalStreams += session.notificationStreams.size;
|
|
2623
|
-
}
|
|
2624
|
-
this._metrics?.gauge('streamable_http_notification_streams', totalStreams, {}, 'Active SSE notification streams');
|
|
2625
2593
|
}
|
|
2626
2594
|
/**
|
|
2627
2595
|
* Stop transport server with graceful shutdown.
|
|
@@ -2630,6 +2598,7 @@ function parseSessionRetentionOptions(options) {
|
|
|
2630
2598
|
*/ stop(timeout) {
|
|
2631
2599
|
if (this._stopPromise) return this._stopPromise;
|
|
2632
2600
|
this._isShuttingDown = true;
|
|
2601
|
+
this._preDispatch.closeAdmission('shutdown');
|
|
2633
2602
|
this._stopRateLimitCleanup();
|
|
2634
2603
|
this._stopSessionSweep();
|
|
2635
2604
|
const shutdownTimeout = timeout ?? 30000;
|
|
@@ -2665,7 +2634,7 @@ function parseSessionRetentionOptions(options) {
|
|
|
2665
2634
|
});
|
|
2666
2635
|
const stopPromise = Promise.all([
|
|
2667
2636
|
serverClosed,
|
|
2668
|
-
this._acceptedWork.join()
|
|
2637
|
+
this._preDispatch.join().then(()=>this._acceptedWork.join())
|
|
2669
2638
|
]).then(()=>{
|
|
2670
2639
|
this.log('info', 'Streamable HTTP transport stopped');
|
|
2671
2640
|
});
|
|
@@ -3144,7 +3113,7 @@ if (shouldShowVersion) {
|
|
|
3144
3113
|
process.exit(0);
|
|
3145
3114
|
}
|
|
3146
3115
|
async function main() {
|
|
3147
|
-
const transportType = process.env.
|
|
3116
|
+
const transportType = process.env.TRACELATTICE_TRANSPORT_TYPE || 'stdio';
|
|
3148
3117
|
const adapter = new __rspack_external__tmcp_adapter_valibot_0faddfa6.ValibotJsonSchemaAdapter();
|
|
3149
3118
|
const server = new __rspack_external_tmcp.McpServer({
|
|
3150
3119
|
name: CLI_NAME,
|
|
@@ -3179,17 +3148,17 @@ async function main() {
|
|
|
3179
3148
|
/**
|
|
3180
3149
|
* Start Streamable HTTP transport (MCP spec recommended)
|
|
3181
3150
|
*/ async function startStreamableHttpTransport(server, thinkingServer, lifecycle) {
|
|
3182
|
-
const { StreamableHttpTransport } = await Promise.resolve(/* import() */).then(__webpack_require__.bind(__webpack_require__, "
|
|
3183
|
-
const port = parseInt(process.env.
|
|
3184
|
-
const host = process.env.
|
|
3151
|
+
const { StreamableHttpTransport } = await Promise.resolve(/* import() */).then(__webpack_require__.bind(__webpack_require__, "q"));
|
|
3152
|
+
const port = parseInt(process.env.TRACELATTICE_STREAMABLE_HTTP_PORT || '9007', 10);
|
|
3153
|
+
const host = process.env.TRACELATTICE_STREAMABLE_HTTP_HOST || 'localhost';
|
|
3185
3154
|
const transportMetrics = thinkingServer.getContainer().resolve('Metrics');
|
|
3186
|
-
const stateful = process.env.
|
|
3155
|
+
const stateful = process.env.TRACELATTICE_STREAMABLE_HTTP_STATEFUL !== 'false';
|
|
3187
3156
|
const streamableTransport = new StreamableHttpTransport({
|
|
3188
3157
|
port,
|
|
3189
3158
|
host,
|
|
3190
|
-
corsOrigin: process.env.
|
|
3191
|
-
enableCors: process.env.
|
|
3192
|
-
allowedHosts: process.env.
|
|
3159
|
+
corsOrigin: process.env.TRACELATTICE_CORS_ORIGIN || '*',
|
|
3160
|
+
enableCors: process.env.TRACELATTICE_ENABLE_CORS !== 'false',
|
|
3161
|
+
allowedHosts: process.env.TRACELATTICE_ALLOWED_HOSTS?.split(',').map((hostValue)=>hostValue.trim()),
|
|
3193
3162
|
metrics: transportMetrics,
|
|
3194
3163
|
stateful
|
|
3195
3164
|
});
|