tracelattice 1.2.5
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/LICENSE +24 -0
- package/README.md +112 -0
- package/dist/ServerConfig.d.ts +229 -0
- package/dist/ServerConfig.d.ts.map +1 -0
- package/dist/ServerConfig.js +121 -0
- package/dist/ServerConfig.js.map +1 -0
- package/dist/__tests__/base-registry.test.d.ts +2 -0
- package/dist/__tests__/base-registry.test.d.ts.map +1 -0
- package/dist/__tests__/base-transport-cov.test.d.ts +2 -0
- package/dist/__tests__/base-transport-cov.test.d.ts.map +1 -0
- package/dist/__tests__/base-transport.test.d.ts +2 -0
- package/dist/__tests__/base-transport.test.d.ts.map +1 -0
- package/dist/__tests__/config-loader.test.d.ts +2 -0
- package/dist/__tests__/config-loader.test.d.ts.map +1 -0
- package/dist/__tests__/connection-pool-cov.test.d.ts +2 -0
- package/dist/__tests__/connection-pool-cov.test.d.ts.map +1 -0
- package/dist/__tests__/connection-pool.test.d.ts +2 -0
- package/dist/__tests__/connection-pool.test.d.ts.map +1 -0
- package/dist/__tests__/container.test.d.ts +2 -0
- package/dist/__tests__/container.test.d.ts.map +1 -0
- package/dist/__tests__/crud.test.d.ts +2 -0
- package/dist/__tests__/crud.test.d.ts.map +1 -0
- package/dist/__tests__/discovery-cache.test.d.ts +2 -0
- package/dist/__tests__/discovery-cache.test.d.ts.map +1 -0
- package/dist/__tests__/errors.test.d.ts +2 -0
- package/dist/__tests__/errors.test.d.ts.map +1 -0
- package/dist/__tests__/factories.test.d.ts +2 -0
- package/dist/__tests__/factories.test.d.ts.map +1 -0
- package/dist/__tests__/health-checker-cov.test.d.ts +2 -0
- package/dist/__tests__/health-checker-cov.test.d.ts.map +1 -0
- package/dist/__tests__/health-checker.test.d.ts +2 -0
- package/dist/__tests__/health-checker.test.d.ts.map +1 -0
- package/dist/__tests__/helpers/factories.d.ts +36 -0
- package/dist/__tests__/helpers/factories.d.ts.map +1 -0
- package/dist/__tests__/helpers/index.d.ts +3 -0
- package/dist/__tests__/helpers/index.d.ts.map +1 -0
- package/dist/__tests__/helpers/timers.d.ts +4 -0
- package/dist/__tests__/helpers/timers.d.ts.map +1 -0
- package/dist/__tests__/history-manager.test.d.ts +2 -0
- package/dist/__tests__/history-manager.test.d.ts.map +1 -0
- package/dist/__tests__/http-helpers-cov.test.d.ts +2 -0
- package/dist/__tests__/http-helpers-cov.test.d.ts.map +1 -0
- package/dist/__tests__/http-transport-cov.test.d.ts +2 -0
- package/dist/__tests__/http-transport-cov.test.d.ts.map +1 -0
- package/dist/__tests__/http-transport.test.d.ts +2 -0
- package/dist/__tests__/http-transport.test.d.ts.map +1 -0
- package/dist/__tests__/input-normalizer.test.d.ts +8 -0
- package/dist/__tests__/input-normalizer.test.d.ts.map +1 -0
- package/dist/__tests__/integration.test.d.ts +2 -0
- package/dist/__tests__/integration.test.d.ts.map +1 -0
- package/dist/__tests__/lib-server.test.d.ts +2 -0
- package/dist/__tests__/lib-server.test.d.ts.map +1 -0
- package/dist/__tests__/memory-persistence.test.d.ts +2 -0
- package/dist/__tests__/memory-persistence.test.d.ts.map +1 -0
- package/dist/__tests__/metrics-integration.test.d.ts +2 -0
- package/dist/__tests__/metrics-integration.test.d.ts.map +1 -0
- package/dist/__tests__/persistence.test.d.ts +2 -0
- package/dist/__tests__/persistence.test.d.ts.map +1 -0
- package/dist/__tests__/reasoning-integration.test.d.ts +11 -0
- package/dist/__tests__/reasoning-integration.test.d.ts.map +1 -0
- package/dist/__tests__/reasoning-types.test.d.ts +2 -0
- package/dist/__tests__/reasoning-types.test.d.ts.map +1 -0
- package/dist/__tests__/request-context.test.d.ts +2 -0
- package/dist/__tests__/request-context.test.d.ts.map +1 -0
- package/dist/__tests__/sanitize.test.d.ts +2 -0
- package/dist/__tests__/sanitize.test.d.ts.map +1 -0
- package/dist/__tests__/schema.test.d.ts +2 -0
- package/dist/__tests__/schema.test.d.ts.map +1 -0
- package/dist/__tests__/sequentialthinking-tools.test.d.ts +2 -0
- package/dist/__tests__/sequentialthinking-tools.test.d.ts.map +1 -0
- package/dist/__tests__/server-config.test.d.ts +2 -0
- package/dist/__tests__/server-config.test.d.ts.map +1 -0
- package/dist/__tests__/skill-discovery.test.d.ts +2 -0
- package/dist/__tests__/skill-discovery.test.d.ts.map +1 -0
- package/dist/__tests__/skill-registry.test.d.ts +2 -0
- package/dist/__tests__/skill-registry.test.d.ts.map +1 -0
- package/dist/__tests__/skill-watcher.test.d.ts +2 -0
- package/dist/__tests__/skill-watcher.test.d.ts.map +1 -0
- package/dist/__tests__/sqlite-persistence.test.d.ts +2 -0
- package/dist/__tests__/sqlite-persistence.test.d.ts.map +1 -0
- package/dist/__tests__/sse-transport-cov.test.d.ts +2 -0
- package/dist/__tests__/sse-transport-cov.test.d.ts.map +1 -0
- package/dist/__tests__/sse-transport.test.d.ts +2 -0
- package/dist/__tests__/sse-transport.test.d.ts.map +1 -0
- package/dist/__tests__/streamable-http-cov.test.d.ts +2 -0
- package/dist/__tests__/streamable-http-cov.test.d.ts.map +1 -0
- package/dist/__tests__/streamable-http-transport.test.d.ts +2 -0
- package/dist/__tests__/streamable-http-transport.test.d.ts.map +1 -0
- package/dist/__tests__/structured-logger.test.d.ts +2 -0
- package/dist/__tests__/structured-logger.test.d.ts.map +1 -0
- package/dist/__tests__/thought-evaluator.test.d.ts +2 -0
- package/dist/__tests__/thought-evaluator.test.d.ts.map +1 -0
- package/dist/__tests__/thought-formatter.test.d.ts +2 -0
- package/dist/__tests__/thought-formatter.test.d.ts.map +1 -0
- package/dist/__tests__/thought-processor.test.d.ts +8 -0
- package/dist/__tests__/thought-processor.test.d.ts.map +1 -0
- package/dist/__tests__/tool-registry-cov.test.d.ts +2 -0
- package/dist/__tests__/tool-registry-cov.test.d.ts.map +1 -0
- package/dist/__tests__/tool-registry.test.d.ts +2 -0
- package/dist/__tests__/tool-registry.test.d.ts.map +1 -0
- package/dist/__tests__/tool-watcher.test.d.ts +2 -0
- package/dist/__tests__/tool-watcher.test.d.ts.map +1 -0
- package/dist/__tests__/worker-manager-cov.test.d.ts +2 -0
- package/dist/__tests__/worker-manager-cov.test.d.ts.map +1 -0
- package/dist/__tests__/worker-manager.test.d.ts +2 -0
- package/dist/__tests__/worker-manager.test.d.ts.map +1 -0
- package/dist/cache/DiscoveryCache.d.ts +269 -0
- package/dist/cache/DiscoveryCache.d.ts.map +1 -0
- package/dist/cache/DiscoveryCache.js +100 -0
- package/dist/cache/DiscoveryCache.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +114 -0
- package/dist/cli.js.map +1 -0
- package/dist/cluster/WorkerManager.d.ts +166 -0
- package/dist/cluster/WorkerManager.d.ts.map +1 -0
- package/dist/cluster/WorkerManager.js +202 -0
- package/dist/cluster/WorkerManager.js.map +1 -0
- package/dist/cluster/worker.d.ts +11 -0
- package/dist/cluster/worker.d.ts.map +1 -0
- package/dist/cluster/worker.js +36 -0
- package/dist/cluster/worker.js.map +1 -0
- package/dist/config/ConfigLoader.d.ts +224 -0
- package/dist/config/ConfigLoader.d.ts.map +1 -0
- package/dist/config/ConfigLoader.js +85 -0
- package/dist/config/ConfigLoader.js.map +1 -0
- package/dist/context/RequestContext.d.ts +61 -0
- package/dist/context/RequestContext.d.ts.map +1 -0
- package/dist/context/RequestContext.js +17 -0
- package/dist/context/RequestContext.js.map +1 -0
- package/dist/contracts/index.d.ts +10 -0
- package/dist/contracts/index.d.ts.map +1 -0
- package/dist/contracts/index.js +1 -0
- package/dist/contracts/interfaces.d.ts +107 -0
- package/dist/contracts/interfaces.d.ts.map +1 -0
- package/dist/contracts/interfaces.js +1 -0
- package/dist/core/HistoryManager.d.ts +514 -0
- package/dist/core/HistoryManager.d.ts.map +1 -0
- package/dist/core/HistoryManager.js +331 -0
- package/dist/core/HistoryManager.js.map +1 -0
- package/dist/core/IHistoryManager.d.ts +100 -0
- package/dist/core/IHistoryManager.d.ts.map +1 -0
- package/dist/core/IHistoryManager.js +1 -0
- package/dist/core/InputNormalizer.d.ts +139 -0
- package/dist/core/InputNormalizer.d.ts.map +1 -0
- package/dist/core/InputNormalizer.js +101 -0
- package/dist/core/InputNormalizer.js.map +1 -0
- package/dist/core/ThoughtEvaluator.d.ts +127 -0
- package/dist/core/ThoughtEvaluator.d.ts.map +1 -0
- package/dist/core/ThoughtEvaluator.js +346 -0
- package/dist/core/ThoughtEvaluator.js.map +1 -0
- package/dist/core/ThoughtFormatter.d.ts +133 -0
- package/dist/core/ThoughtFormatter.d.ts.map +1 -0
- package/dist/core/ThoughtFormatter.js +70 -0
- package/dist/core/ThoughtFormatter.js.map +1 -0
- package/dist/core/ThoughtProcessor.d.ts +218 -0
- package/dist/core/ThoughtProcessor.d.ts.map +1 -0
- package/dist/core/ThoughtProcessor.js +205 -0
- package/dist/core/ThoughtProcessor.js.map +1 -0
- package/dist/core/reasoning.d.ts +169 -0
- package/dist/core/reasoning.d.ts.map +1 -0
- package/dist/core/reasoning.js +1 -0
- package/dist/core/step.d.ts +45 -0
- package/dist/core/step.d.ts.map +1 -0
- package/dist/core/step.js +1 -0
- package/dist/core/thought.d.ts +190 -0
- package/dist/core/thought.d.ts.map +1 -0
- package/dist/core/thought.js +1 -0
- package/dist/di/Container.d.ts +226 -0
- package/dist/di/Container.d.ts.map +1 -0
- package/dist/di/Container.js +96 -0
- package/dist/di/Container.js.map +1 -0
- package/dist/di/ServiceRegistry.d.ts +32 -0
- package/dist/di/ServiceRegistry.d.ts.map +1 -0
- package/dist/di/ServiceRegistry.js +1 -0
- package/dist/errors.d.ts +482 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +108 -0
- package/dist/errors.js.map +1 -0
- package/dist/health/HealthChecker.d.ts +73 -0
- package/dist/health/HealthChecker.d.ts.map +1 -0
- package/dist/health/HealthChecker.js +69 -0
- package/dist/health/HealthChecker.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1 -0
- package/dist/lib.d.ts +205 -0
- package/dist/lib.d.ts.map +1 -0
- package/dist/lib.js +219 -0
- package/dist/lib.js.map +1 -0
- package/dist/logger/NullLogger.d.ts +154 -0
- package/dist/logger/NullLogger.d.ts.map +1 -0
- package/dist/logger/NullLogger.js +24 -0
- package/dist/logger/NullLogger.js.map +1 -0
- package/dist/logger/StructuredLogger.d.ts +327 -0
- package/dist/logger/StructuredLogger.d.ts.map +1 -0
- package/dist/logger/StructuredLogger.js +72 -0
- package/dist/logger/StructuredLogger.js.map +1 -0
- package/dist/metrics/__tests__/metrics.test.d.ts +2 -0
- package/dist/metrics/__tests__/metrics.test.d.ts.map +1 -0
- package/dist/metrics/metrics.impl.d.ts +252 -0
- package/dist/metrics/metrics.impl.d.ts.map +1 -0
- package/dist/metrics/metrics.impl.js +197 -0
- package/dist/metrics/metrics.impl.js.map +1 -0
- package/dist/persistence/FilePersistence.d.ts +66 -0
- package/dist/persistence/FilePersistence.d.ts.map +1 -0
- package/dist/persistence/FilePersistence.js +132 -0
- package/dist/persistence/FilePersistence.js.map +1 -0
- package/dist/persistence/MemoryPersistence.d.ts +68 -0
- package/dist/persistence/MemoryPersistence.d.ts.map +1 -0
- package/dist/persistence/MemoryPersistence.js +51 -0
- package/dist/persistence/MemoryPersistence.js.map +1 -0
- package/dist/persistence/PersistenceBackend.d.ts +69 -0
- package/dist/persistence/PersistenceBackend.d.ts.map +1 -0
- package/dist/persistence/PersistenceBackend.js +1 -0
- package/dist/persistence/PersistenceFactory.d.ts +21 -0
- package/dist/persistence/PersistenceFactory.d.ts.map +1 -0
- package/dist/persistence/PersistenceFactory.js +25 -0
- package/dist/persistence/PersistenceFactory.js.map +1 -0
- package/dist/persistence/SqlitePersistence.d.ts +60 -0
- package/dist/persistence/SqlitePersistence.d.ts.map +1 -0
- package/dist/persistence/SqlitePersistence.js +136 -0
- package/dist/persistence/SqlitePersistence.js.map +1 -0
- package/dist/pool/ConnectionPool.d.ts +215 -0
- package/dist/pool/ConnectionPool.d.ts.map +1 -0
- package/dist/pool/ConnectionPool.js +187 -0
- package/dist/pool/ConnectionPool.js.map +1 -0
- package/dist/registry/BaseRegistry.d.ts +203 -0
- package/dist/registry/BaseRegistry.d.ts.map +1 -0
- package/dist/registry/BaseRegistry.js +165 -0
- package/dist/registry/BaseRegistry.js.map +1 -0
- package/dist/registry/SkillRegistry.d.ts +69 -0
- package/dist/registry/SkillRegistry.d.ts.map +1 -0
- package/dist/registry/SkillRegistry.js +88 -0
- package/dist/registry/SkillRegistry.js.map +1 -0
- package/dist/registry/ToolRegistry.d.ts +69 -0
- package/dist/registry/ToolRegistry.d.ts.map +1 -0
- package/dist/registry/ToolRegistry.js +93 -0
- package/dist/registry/ToolRegistry.js.map +1 -0
- package/dist/sanitize.d.ts +63 -0
- package/dist/sanitize.d.ts.map +1 -0
- package/dist/sanitize.js +14 -0
- package/dist/sanitize.js.map +1 -0
- package/dist/schema.d.ts +531 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +204 -0
- package/dist/schema.js.map +1 -0
- package/dist/telemetry/Telemetry.d.ts +36 -0
- package/dist/telemetry/Telemetry.d.ts.map +1 -0
- package/dist/telemetry/Telemetry.js +68 -0
- package/dist/telemetry/Telemetry.js.map +1 -0
- package/dist/telemetry/__tests__/Telemetry.test.d.ts +2 -0
- package/dist/telemetry/__tests__/Telemetry.test.d.ts.map +1 -0
- package/dist/transport/BaseTransport.d.ts +184 -0
- package/dist/transport/BaseTransport.d.ts.map +1 -0
- package/dist/transport/BaseTransport.js +200 -0
- package/dist/transport/BaseTransport.js.map +1 -0
- package/dist/transport/HttpHelpers.d.ts +60 -0
- package/dist/transport/HttpHelpers.d.ts.map +1 -0
- package/dist/transport/HttpHelpers.js +50 -0
- package/dist/transport/HttpHelpers.js.map +1 -0
- package/dist/transport/HttpTransport.d.ts +134 -0
- package/dist/transport/HttpTransport.d.ts.map +1 -0
- package/dist/transport/HttpTransport.js +175 -0
- package/dist/transport/HttpTransport.js.map +1 -0
- package/dist/transport/SseTransport.d.ts +133 -0
- package/dist/transport/SseTransport.d.ts.map +1 -0
- package/dist/transport/SseTransport.js +318 -0
- package/dist/transport/SseTransport.js.map +1 -0
- package/dist/transport/StreamableHttpTransport.d.ts +224 -0
- package/dist/transport/StreamableHttpTransport.d.ts.map +1 -0
- package/dist/transport/StreamableHttpTransport.js +407 -0
- package/dist/transport/StreamableHttpTransport.js.map +1 -0
- package/dist/types/disposable.d.ts +22 -0
- package/dist/types/disposable.d.ts.map +1 -0
- package/dist/types/disposable.js +1 -0
- package/dist/types/server-config.d.ts +32 -0
- package/dist/types/server-config.d.ts.map +1 -0
- package/dist/types/server-config.js +1 -0
- package/dist/types/skill.d.ts +69 -0
- package/dist/types/skill.d.ts.map +1 -0
- package/dist/types/skill.js +1 -0
- package/dist/types/tool.d.ts +68 -0
- package/dist/types/tool.d.ts.map +1 -0
- package/dist/types/tool.js +1 -0
- package/dist/watchers/SkillWatcher.d.ts +132 -0
- package/dist/watchers/SkillWatcher.d.ts.map +1 -0
- package/dist/watchers/SkillWatcher.js +73 -0
- package/dist/watchers/SkillWatcher.js.map +1 -0
- package/dist/watchers/ToolWatcher.d.ts +109 -0
- package/dist/watchers/ToolWatcher.d.ts.map +1 -0
- package/dist/watchers/ToolWatcher.js +71 -0
- package/dist/watchers/ToolWatcher.js.map +1 -0
- package/package.json +95 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transport/SseTransport.js","sources":["../../src/transport/SseTransport.ts"],"sourcesContent":["/**\n * SSE (Server-Sent Events) Transport implementation.\n *\n * This transport allows multiple concurrent connections over HTTP using Server-Sent Events,\n * enabling multi-user scenarios and horizontal scaling.\n *\n * When a ConnectionPool is provided, each SSE client gets an isolated session with its own\n * thought history. Without a pool, all clients share a single server instance (backward compatible).\n *\n * @example\n * ```typescript\n * const transport = new SseTransport({\n * port: 3000,\n * host: 'localhost'\n * });\n * await transport.connect(server);\n * ```\n */\n\nimport { createServer, IncomingMessage, ServerResponse } from 'node:http';\nimport { URL } from 'node:url';\nimport type { McpServer } from 'tmcp';\nimport { safeParse } from 'valibot';\nimport type { IMetrics } from '../contracts/index.js';\nimport type { ConnectionPool } from '../pool/ConnectionPool.js';\nimport { JsonRpcRequestSchema } from '../schema.js';\nimport { BaseTransport, type TransportOptions } from './BaseTransport.js';\n/**\n * SSE-specific transport options extending base TransportOptions.\n */\nexport interface SseTransportOptions extends TransportOptions {\n\tpath?: string;\n\tmetrics?: IMetrics;\n\t/**\n\t * Optional connection pool for per-session state isolation.\n\t * When provided, each SSE client gets an isolated thought history.\n\t * When omitted, all clients share a single server instance (backward compatible).\n\t */\n\tconnectionPool?: ConnectionPool;\n}\n\n/**\n * SSE Transport for MCP server over HTTP.\n *\n * This transport uses Server-Sent Events (SSE) to communicate with clients,\n * allowing multiple concurrent connections and web-based clients.\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 *\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 */\nexport class SseTransport extends BaseTransport {\n\tprivate _server: ReturnType<typeof createServer>;\n\tprivate _path: string;\n\tprivate _clients: Set<ServerResponse> = new Set();\n\tprivate _clientSessionMap: Map<ServerResponse, string> = new Map();\n\tprivate _messageQueue: Map<string, unknown[]> = new Map();\n\tprivate _metrics?: IMetrics;\n\tprivate _connectionPool?: ConnectionPool;\n\n\tconstructor(options: SseTransportOptions = {}) {\n\t\tsuper(options);\n\t\tthis._path = options.path ?? '/sse';\n\t\tthis._metrics = options.metrics;\n\t\tthis._connectionPool = options.connectionPool;\n\t\tthis._updateActiveConnectionsMetric();\n\n\t\tthis._server = createServer((req, res) => this._handleRequest(req, res));\n\t}\n\n\t/**\n\t * Connect MCP server to this transport.\n\t *\n\t * @param mcpServer - The MCP server instance\n\t */\n\tasync connect(mcpServer: McpServer): Promise<void> {\n\t\tthis._mcpServer = mcpServer;\n\n\t\treturn new Promise((resolve) => {\n\t\t\tthis._server.listen(this._port, this._host, () => {\n\t\t\t\tthis.log('info', `SSE transport listening on http://${this._host}:${this._port}`);\n\t\t\t\tresolve();\n\t\t\t});\n\t\t});\n\t}\n\n\tprivate _mcpServer: McpServer | null = null;\n\n\t/**\n\t * Handle incoming HTTP requests\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, { transport: 'sse', method: requestMethod, path: requestPath }, 'Total HTTP requests');\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, { transport: 'sse', path: requestPath });\n\t\t});\n\t\tif (!this.validateHostHeader(req)) {\n\t\t\tthis._metrics?.counter('http_request_errors_total', 1, { transport: 'sse', error_type: 'forbidden' }, 'Total HTTP request errors');\n\t\t\tres.writeHead(403, { 'Content-Type': 'application/json' });\n\t\t\tres.end(JSON.stringify({ error: 'Forbidden - invalid host header' }));\n\t\t\treturn;\n\t\t}\n\n\t\tconst url = new URL(req.url || '', `http://${req.headers.host}`);\n\n\t\t// Check rate limit first\n\t\tconst clientIp = this.getClientIp(req);\n\t\tif (this.checkRateLimit(clientIp)) {\n\t\t\tthis._metrics?.counter('http_request_errors_total', 1, { transport: 'sse', error_type: 'rate_limit' }, 'Total HTTP request errors');\n\t\t\tres.writeHead(429, {\n\t\t\t\t'Content-Type': 'application/json',\n\t\t\t\t'Retry-After': '60',\n\t\t\t});\n\t\t\tres.end(JSON.stringify({ error: 'Too many requests' }));\n\t\t\treturn;\n\t\t}\n\n\t\t// Validate CORS origin\n\t\tif (!this.validateCorsOrigin(req)) {\n\t\t\tthis._metrics?.counter('http_request_errors_total', 1, { transport: 'sse', error_type: 'forbidden' }, 'Total HTTP request errors');\n\t\t\tres.writeHead(403, { 'Content-Type': 'application/json' });\n\t\t\tres.end(JSON.stringify({ error: 'Forbidden - invalid origin' }));\n\t\t\treturn;\n\t\t}\n\n\t\t// Set CORS headers\n\t\tthis.setCorsHeaders(res);\n\n\t\t// Sanitize query parameters\n\t\tconst sanitizedParams = this.sanitizeQueryParams(url);\n\n\t\t// Validate session ID if present\n\t\tif (sanitizedParams.session || sanitizedParams.sessionId) {\n\t\t\tconst sessionId = (sanitizedParams.session ?? sanitizedParams.sessionId)!;\n\t\t\tif (!this.validateSessionId(sessionId)) {\n\t\t\t\tthis._metrics?.counter('http_request_errors_total', 1, { transport: 'sse', error_type: 'validation' }, 'Total HTTP request errors');\n\t\t\t\tres.writeHead(400, { 'Content-Type': 'application/json' });\n\t\t\t\tres.end(JSON.stringify({ error: 'Invalid session ID format' }));\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\t// Handle CORS preflight\n\t\tif (this._enableCors && req.method === 'OPTIONS') {\n\t\t\tres.writeHead(204);\n\t\t\tres.end();\n\t\t\treturn;\n\t\t}\n\n\t\t// Handle SSE endpoint\n\t\tif (url.pathname === this._path && req.method === 'GET') {\n\t\t\tawait this._handleSseConnection(req, res, sanitizedParams);\n\t\t\treturn;\n\t\t}\n\n\t\t// Handle message endpoint (for receiving messages from clients)\n\t\tif (url.pathname === `${this._path}/message` && req.method === 'POST') {\n\t\t\tawait this._handleMessage(req, res, sanitizedParams);\n\t\t\treturn;\n\t\t}\n\n\t\t// Handle health check (liveness)\n\t\tif (url.pathname === '/health') {\n\t\t\tthis._handleHealthCheck(res);\n\t\t\treturn;\n\t\t}\n\n\t\t// Handle readiness check\n\t\tif (url.pathname === '/ready') {\n\t\t\tawait this._handleReadinessCheck(res);\n\t\t\treturn;\n\t\t}\n\n\n\t\t// 404 for unknown paths\n\t\tres.writeHead(404, { 'Content-Type': 'text/plain' });\n\t\tres.end('Not Found');\n\t}\n\n\t/**\n\t * Handle health check (liveness) endpoint\n\t */\n\tprivate _handleHealthCheck(res: ServerResponse): void {\n\t\tconst healthData: Record<string, unknown> = { status: 'healthy', clients: this._clients.size };\n\t\tif (this._connectionPool) {\n\t\t\tconst poolStats = this._connectionPool.getStats();\n\t\t\thealthData.pool = poolStats;\n\t\t}\n\t\tif (this._healthChecker) {\n\t\t\tconst liveness = this._healthChecker.checkLiveness();\n\t\t\thealthData.liveness = liveness;\n\t\t}\n\t\tres.writeHead(200, { 'Content-Type': 'application/json' });\n\t\tres.end(JSON.stringify(healthData));\n\t}\n\n\t/**\n\t * Handle readiness check endpoint\n\t */\n\tprivate async _handleReadinessCheck(res: ServerResponse): Promise<void> {\n\t\tif (this._healthChecker) {\n\t\t\tconst readiness = await this._healthChecker.checkReadiness();\n\t\t\tconst statusCode = readiness.status === 'ok' ? 200 : 503;\n\t\t\tres.writeHead(statusCode, { 'Content-Type': 'application/json' });\n\t\t\tres.end(JSON.stringify(readiness));\n\t\t} else {\n\t\t\tres.writeHead(200, { 'Content-Type': 'application/json' });\n\t\t\tres.end(JSON.stringify({ status: 'ok', timestamp: new Date().toISOString(), components: {} }));\n\t\t}\n\t}\n\n\t/**\n\t * Handle new SSE connection\n\t */\n\tprivate async _handleSseConnection(\n\t\treq: IncomingMessage,\n\t\tres: ServerResponse,\n\t\tparams: Record<string, string>\n\t): Promise<void> {\n\t\t// Set SSE headers\n\t\tres.writeHead(200, {\n\t\t\t'Content-Type': 'text/event-stream',\n\t\t\t'Cache-Control': 'no-cache',\n\t\t\tConnection: 'keep-alive',\n\t\t});\n\n\t\t// Resolve session ID when pool is active\n\t\tlet sessionId: string | undefined;\n\t\tif (this._connectionPool) {\n\t\t\tconst requestedSession = params.session ?? params.sessionId;\n\t\t\tif (requestedSession && this._connectionPool.getSessionInfo(requestedSession)) {\n\t\t\t\tsessionId = requestedSession;\n\t\t\t} else {\n\t\t\t\ttry {\n\t\t\t\t\tsessionId = await this._connectionPool.createSession();\n\t\t\t\t} catch (error) {\n\t\t\t\t\tres.write(`event: error\\n`);\n\t\t\t\t\tres.write(`data: ${JSON.stringify({ error: error instanceof Error ? error.message : 'Failed to create session' })}\\n\\n`);\n\t\t\t\t\tres.end();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis._clientSessionMap.set(res, sessionId);\n\t\t\tthis._updatePoolMetrics();\n\t\t}\n\n\t\t// Send initial connection event\n\t\tconst connectedPayload: Record<string, unknown> = { timestamp: Date.now() };\n\t\tif (sessionId) {\n\t\t\tconnectedPayload.sessionId = sessionId;\n\t\t}\n\t\tthis._sendSseEvent(res, 'connected', connectedPayload);\n\n\t\t// Add to clients\n\t\tthis._clients.add(res);\n\t\tthis._updateActiveConnectionsMetric();\n\n\t\t// Handle client disconnect\n\t\treq.on('close', () => {\n\t\t\tthis._clients.delete(res);\n\t\t\tthis._clientSessionMap.delete(res);\n\t\t\tthis._updateActiveConnectionsMetric();\n\t\t});\n\n\t\t// Send any queued messages\n\t\tconst clientId = this._generateClientId();\n\t\tconst queued = this._messageQueue.get(clientId);\n\t\tif (queued) {\n\t\t\tfor (const message of queued) {\n\t\t\t\tthis._sendSseEvent(res, 'message', message);\n\t\t\t}\n\t\t\tthis._messageQueue.delete(clientId);\n\t\t}\n\t}\n\n\t/**\n\t * Handle incoming message from client\n\t */\n\tprivate async _handleMessage(\n\t\treq: IncomingMessage,\n\t\tres: ServerResponse,\n\t\t_params: Record<string, string>\n\t): Promise<void> {\n\t\tlet body = '';\n\n\t\tfor await (const chunk of req) {\n\t\t\tbody += chunk.toString();\n\t\t}\n\n\t\ttry {\n\t\t\tconst jsonRpcRequest = JSON.parse(body);\n\t\t\tconst parseResult = safeParse(JsonRpcRequestSchema, jsonRpcRequest);\n\t\t\tif (!parseResult.success) {\n\t\t\t\tthis._metrics?.counter('http_request_errors_total', 1, { transport: 'sse', error_type: 'validation' }, 'Total HTTP request errors');\n\t\t\t\tres.writeHead(200, { 'Content-Type': 'application/json' });\n\t\t\t\tres.end(\n\t\t\t\t\tJSON.stringify({\n\t\t\t\t\t\tjsonrpc: '2.0',\n\t\t\t\t\t\tid: jsonRpcRequest?.id ?? null,\n\t\t\t\t\t\terror: {\n\t\t\t\t\t\t\tcode: -32600,\n\t\t\t\t\t\t\tmessage: 'Invalid Request',\n\t\t\t\t\t\t\tdata: parseResult.issues,\n\t\t\t\t\t\t},\n\t\t\t\t\t})\n\t\t\t\t);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Process message through MCP server\n\t\t\tif (this._mcpServer) {\n\t\t\t\tconst response = await this._mcpServer.receive(jsonRpcRequest, {\n\t\t\t\t\tsessionInfo: {},\n\t\t\t\t});\n\t\t\t\tres.writeHead(200, {\n\t\t\t\t\t'Content-Type': 'application/json',\n\t\t\t\t});\n\n\t\t\t\tif (response) {\n\t\t\t\t\tres.end(JSON.stringify(response));\n\t\t\t\t} else {\n\t\t\t\t\tres.end(JSON.stringify({ jsonrpc: '2.0', id: jsonRpcRequest?.id ?? null, result: null }));\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthis._metrics?.counter('http_request_errors_total', 1, { transport: 'sse', error_type: 'server_not_ready' }, 'Total HTTP request errors');\n\t\t\t\tres.writeHead(503, { 'Content-Type': 'application/json' });\n\t\t\t\tres.end(JSON.stringify({ error: 'Server not ready' }));\n\t\t\t}\n\t\t} catch {\n\t\t\tthis._metrics?.counter('http_request_errors_total', 1, { transport: 'sse', error_type: 'parse_error' }, 'Total HTTP request errors');\n\t\t\tres.writeHead(400, { 'Content-Type': 'application/json' });\n\t\t\tres.end(JSON.stringify({ error: 'Invalid JSON' }));\n\t\t}\n\t}\n\n\t/**\n\t * Send an SSE event to a specific client\n\t */\n\tprivate _sendSseEvent(res: ServerResponse, event: string, data: unknown): void {\n\t\ttry {\n\t\t\tres.write(`event: ${event}\\n`);\n\t\t\tres.write(`data: ${JSON.stringify(data)}\\n\\n`);\n\t\t} catch {\n\t\t\t// Client disconnected\n\t\t\tthis._clients.delete(res);\n\t\t\tthis._updateActiveConnectionsMetric();\n\t\t}\n\t}\n\n\tprivate _updateActiveConnectionsMetric(): void {\n\t\tthis._metrics?.gauge(\n\t\t\t'sse_active_connections',\n\t\t\tthis._clients.size,\n\t\t\t{},\n\t\t\t'Current active SSE connections'\n\t\t);\n\t}\n\n\tprivate _updatePoolMetrics(): void {\n\t\tif (!this._connectionPool || !this._metrics) {\n\t\t\treturn;\n\t\t}\n\t\tconst stats = this._connectionPool.getStats();\n\t\tthis._metrics.gauge(\n\t\t\t'sse_pool_active_sessions',\n\t\t\tstats.activeSessions,\n\t\t\t{},\n\t\t\t'Active sessions in connection pool'\n\t\t);\n\t\tthis._metrics.gauge(\n\t\t\t'sse_pool_total_sessions',\n\t\t\tstats.totalSessions,\n\t\t\t{},\n\t\t\t'Total sessions in connection pool'\n\t\t);\n\t\tthis._metrics.gauge(\n\t\t\t'sse_pool_max_sessions',\n\t\t\tstats.maxSessions,\n\t\t\t{},\n\t\t\t'Maximum sessions in connection pool'\n\t\t);\n\t}\n\n\t/**\n\t * Broadcast a message to all connected clients\n\t */\n\tbroadcast(event: string, data: unknown): void {\n\t\tfor (const client of this._clients) {\n\t\t\tthis._sendSseEvent(client, event, data);\n\t\t}\n\t}\n\n\t/**\n\t * Generate a unique client ID\n\t */\n\tprivate _generateClientId(): string {\n\t\treturn `client_${Date.now()}_${Math.random().toString(36).substring(2, 11)}`;\n\t}\n\n\t/**\n\t * Get number of connected clients\n\t */\n\tget clientCount(): number {\n\t\treturn this._clients.size;\n\t}\n\n\t/**\n\t * Get the connection pool, if one was configured.\n\t */\n\tget connectionPool(): ConnectionPool | undefined {\n\t\treturn this._connectionPool;\n\t}\n\n\t/**\n\t * Stop the transport server with graceful shutdown.\n\t *\n\t * @param timeout - Maximum time to wait for requests to drain (not used for SSE)\n\t * @returns Promise that resolves when shutdown is complete\n\t */\n\tasync stop(_timeout?: number): Promise<void> {\n\t\tthis._isShuttingDown = true;\n\t\tthis._stopRateLimitCleanup();\n\n\t\t// Terminate connection pool if present\n\t\tif (this._connectionPool) {\n\t\t\tawait this._connectionPool.terminate();\n\t\t}\n\n\t\treturn new Promise((resolve) => {\n\t\t\t// Close all client connections\n\t\t\tfor (const client of this._clients) {\n\t\t\t\ttry {\n\t\t\t\t\tclient.end();\n\t\t\t\t} catch {\n\t\t\t\t\t// Ignore errors\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis._clients.clear();\n\t\t\tthis._clientSessionMap.clear();\n\t\t\tthis._updateActiveConnectionsMetric();\n\n\t\t\t// Close server\n\t\t\tthis._server.close(() => {\n\t\t\t\tthis.log('info', 'SSE transport stopped');\n\t\t\t\tresolve();\n\t\t\t});\n\t\t});\n\t}\n}\n\n/**\n * Create an SSE transport with given options.\n *\n * @param options - Transport configuration\n * @returns A configured SSE transport\n *\n * @example\n * ```typescript\n * const transport = createSseTransport({ port: 3000 });\n * await transport.connect(mcpServer);\n * ```\n */\nexport function createSseTransport(options: SseTransportOptions = {}): SseTransport {\n\treturn new SseTransport(options);\n}\n"],"names":["SseTransport","BaseTransport","Set","Map","options","createServer","req","res","mcpServer","Promise","resolve","startTime","Date","requestPath","requestMethod","durationSeconds","JSON","url","URL","clientIp","sanitizedParams","sessionId","healthData","poolStats","liveness","readiness","statusCode","params","requestedSession","error","Error","connectedPayload","clientId","queued","message","_params","body","chunk","jsonRpcRequest","parseResult","safeParse","JsonRpcRequestSchema","response","event","data","stats","client","Math","_timeout","createSseTransport"],"mappings":"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"}
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Streamable HTTP Transport implementation (MCP spec recommended transport).
|
|
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
|
+
* Key features:
|
|
8
|
+
* - POST /mcp for JSON-RPC requests (main MCP endpoint)
|
|
9
|
+
* - GET /mcp for optional SSE server-to-client notifications
|
|
10
|
+
* - Session management via Mcp-Session-Id header
|
|
11
|
+
* - Supports both stateful (session-based) and stateless (per-request) modes
|
|
12
|
+
* - Health endpoints (/health, /ready)
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```typescript
|
|
16
|
+
* const transport = new StreamableHttpTransport({
|
|
17
|
+
* port: 3000,
|
|
18
|
+
* host: 'localhost',
|
|
19
|
+
* stateful: true,
|
|
20
|
+
* });
|
|
21
|
+
* await transport.connect(server);
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
import type { McpServer } from 'tmcp';
|
|
25
|
+
import type { IMetrics } from '../contracts/index.js';
|
|
26
|
+
import { BaseTransport, type TransportOptions } from './BaseTransport.js';
|
|
27
|
+
/**
|
|
28
|
+
* MCP Streamable HTTP transport options extending base TransportOptions.
|
|
29
|
+
*/
|
|
30
|
+
export interface StreamableHttpTransportOptions extends TransportOptions {
|
|
31
|
+
/**
|
|
32
|
+
* Path for the MCP endpoint
|
|
33
|
+
* @default '/mcp'
|
|
34
|
+
*/
|
|
35
|
+
path?: string;
|
|
36
|
+
/**
|
|
37
|
+
* Metrics collector for transport telemetry
|
|
38
|
+
*/
|
|
39
|
+
metrics?: IMetrics;
|
|
40
|
+
/**
|
|
41
|
+
* Prometheus metrics provider function
|
|
42
|
+
*/
|
|
43
|
+
metricsProvider?: () => string;
|
|
44
|
+
/**
|
|
45
|
+
* Enable stateful session-based mode.
|
|
46
|
+
* When true, sessions are tracked via Mcp-Session-Id header.
|
|
47
|
+
* When false, each request is processed independently (stateless).
|
|
48
|
+
* @default true
|
|
49
|
+
*/
|
|
50
|
+
stateful?: boolean;
|
|
51
|
+
/**
|
|
52
|
+
* Custom session ID generator function.
|
|
53
|
+
* @default () => randomUUID()
|
|
54
|
+
*/
|
|
55
|
+
sessionIdGenerator?: () => string;
|
|
56
|
+
/**
|
|
57
|
+
* Enable request body size limit
|
|
58
|
+
* @default true
|
|
59
|
+
*/
|
|
60
|
+
enableBodySizeLimit?: boolean;
|
|
61
|
+
/**
|
|
62
|
+
* Maximum request body size in bytes
|
|
63
|
+
* @default 10485760 (10MB)
|
|
64
|
+
*/
|
|
65
|
+
maxBodySize?: number;
|
|
66
|
+
/**
|
|
67
|
+
* Request timeout in milliseconds
|
|
68
|
+
* @default 30000 (30 seconds)
|
|
69
|
+
*/
|
|
70
|
+
requestTimeout?: number;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Streamable HTTP Transport for MCP server.
|
|
74
|
+
*
|
|
75
|
+
* This transport implements the MCP Streamable HTTP specification,
|
|
76
|
+
* providing JSON-RPC over HTTP with optional session management
|
|
77
|
+
* and server-to-client SSE notification streams.
|
|
78
|
+
*
|
|
79
|
+
* @remarks
|
|
80
|
+
* **Security Features (inherited from BaseTransport):**
|
|
81
|
+
* - Session ID validation (alphanumeric, max 64 chars)
|
|
82
|
+
* - Query parameter sanitization (whitelist allowed keys)
|
|
83
|
+
* - Rate limiting per IP (configurable, default 100 req/min)
|
|
84
|
+
* - CORS origin validation
|
|
85
|
+
* - Host header validation
|
|
86
|
+
*
|
|
87
|
+
* **MCP Streamable HTTP Spec Compliance:**
|
|
88
|
+
* - POST /mcp — JSON-RPC method calls
|
|
89
|
+
* - GET /mcp — SSE notification stream (server-to-client)
|
|
90
|
+
* - Mcp-Session-Id header for session management
|
|
91
|
+
* - Content-Type: application/json for JSON-RPC responses
|
|
92
|
+
* - Content-Type: text/event-stream for SSE notification streams
|
|
93
|
+
*
|
|
94
|
+
* **HTTP Status Code Mapping:**
|
|
95
|
+
* - 200: Success (JSON-RPC response or SSE stream)
|
|
96
|
+
* - 202: Accepted (JSON-RPC notification, no response body)
|
|
97
|
+
* - 204: CORS Preflight (empty body)
|
|
98
|
+
* - 400: Bad Request (invalid JSON, invalid session ID)
|
|
99
|
+
* - 403: Forbidden (invalid CORS, invalid host)
|
|
100
|
+
* - 404: Not Found
|
|
101
|
+
* - 405: Method Not Allowed
|
|
102
|
+
* - 413: Payload Too Large
|
|
103
|
+
* - 429: Too Many Requests
|
|
104
|
+
* - 500: Internal Server Error
|
|
105
|
+
* - 503: Server Not Ready / Shutting Down
|
|
106
|
+
*/
|
|
107
|
+
export declare class StreamableHttpTransport extends BaseTransport {
|
|
108
|
+
private _server;
|
|
109
|
+
private _mcpServer;
|
|
110
|
+
private _path;
|
|
111
|
+
private _stateful;
|
|
112
|
+
private _sessionIdGenerator;
|
|
113
|
+
private _sessions;
|
|
114
|
+
private _requestCount;
|
|
115
|
+
private _activeRequests;
|
|
116
|
+
private _bodySizeLimitEnabled;
|
|
117
|
+
private _maxBodySize;
|
|
118
|
+
private _requestTimeout;
|
|
119
|
+
private _metrics?;
|
|
120
|
+
private _metricsProvider;
|
|
121
|
+
constructor(options?: StreamableHttpTransportOptions);
|
|
122
|
+
/**
|
|
123
|
+
* Get number of active sessions (stateful) or active requests (stateless).
|
|
124
|
+
*/
|
|
125
|
+
get clientCount(): number;
|
|
126
|
+
/**
|
|
127
|
+
* Get the total number of requests handled.
|
|
128
|
+
*/
|
|
129
|
+
get requestCount(): number;
|
|
130
|
+
/**
|
|
131
|
+
* Connects MCP server to this transport and starts listening.
|
|
132
|
+
*/
|
|
133
|
+
connect(mcpServer: McpServer): Promise<void>;
|
|
134
|
+
/**
|
|
135
|
+
* Route and handle incoming HTTP requests.
|
|
136
|
+
*/
|
|
137
|
+
private _handleRequest;
|
|
138
|
+
/**
|
|
139
|
+
* Send a JSON-RPC error response.
|
|
140
|
+
*/
|
|
141
|
+
private _sendJsonRpcError;
|
|
142
|
+
/**
|
|
143
|
+
* Handle POST /mcp — JSON-RPC method calls.
|
|
144
|
+
*
|
|
145
|
+
* Per the MCP Streamable HTTP spec:
|
|
146
|
+
* - Accepts JSON-RPC request bodies
|
|
147
|
+
* - Returns Mcp-Session-Id header for new sessions (stateful mode)
|
|
148
|
+
* - Validates Mcp-Session-Id for existing sessions (stateful mode)
|
|
149
|
+
* - Content-Type: application/json for responses
|
|
150
|
+
*/
|
|
151
|
+
private _handleMcpPost;
|
|
152
|
+
/**
|
|
153
|
+
* Handle GET /mcp — Optional SSE notification stream.
|
|
154
|
+
*
|
|
155
|
+
* Per the MCP Streamable HTTP spec, clients may open a GET request
|
|
156
|
+
* to receive server-initiated notifications as SSE events.
|
|
157
|
+
* Requires a valid Mcp-Session-Id in stateful mode.
|
|
158
|
+
*/
|
|
159
|
+
private _handleMcpGet;
|
|
160
|
+
/**
|
|
161
|
+
* Resolve or create a session for a stateful request.
|
|
162
|
+
*
|
|
163
|
+
* @returns Session ID string on success, or `false` if the response was already sent (error).
|
|
164
|
+
*/
|
|
165
|
+
private _resolveSession;
|
|
166
|
+
/**
|
|
167
|
+
* Extract Mcp-Session-Id from request headers.
|
|
168
|
+
*/
|
|
169
|
+
private _getSessionIdFromHeader;
|
|
170
|
+
/**
|
|
171
|
+
* Read the request body with optional size limit enforcement.
|
|
172
|
+
*
|
|
173
|
+
* @returns Body string, or null if the body exceeds the size limit.
|
|
174
|
+
*/
|
|
175
|
+
private _readRequestBody;
|
|
176
|
+
/**
|
|
177
|
+
* Send an SSE event to a specific client response stream.
|
|
178
|
+
*/
|
|
179
|
+
private _sendSseEvent;
|
|
180
|
+
/**
|
|
181
|
+
* Broadcast a notification to all SSE streams in a given session.
|
|
182
|
+
*
|
|
183
|
+
* @param sessionId - Target session ID
|
|
184
|
+
* @param event - SSE event name
|
|
185
|
+
* @param data - Event payload
|
|
186
|
+
*/
|
|
187
|
+
broadcastToSession(sessionId: string, event: string, data: unknown): void;
|
|
188
|
+
/**
|
|
189
|
+
* Handle GET /metrics endpoint.
|
|
190
|
+
*/
|
|
191
|
+
private _handleMetrics;
|
|
192
|
+
/**
|
|
193
|
+
* Handle GET /health — Liveness check.
|
|
194
|
+
*/
|
|
195
|
+
private _handleHealthCheck;
|
|
196
|
+
/**
|
|
197
|
+
* Handle GET /ready — Readiness check.
|
|
198
|
+
*/
|
|
199
|
+
private _handleReadinessCheck;
|
|
200
|
+
/**
|
|
201
|
+
* Update session-related metrics.
|
|
202
|
+
*/
|
|
203
|
+
private _updateSessionMetrics;
|
|
204
|
+
/**
|
|
205
|
+
* Stop transport server with graceful shutdown.
|
|
206
|
+
*
|
|
207
|
+
* @param timeout - Maximum time to wait for in-flight requests (default: 30s)
|
|
208
|
+
*/
|
|
209
|
+
stop(timeout?: number): Promise<void>;
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Create a Streamable HTTP transport with given options.
|
|
213
|
+
*
|
|
214
|
+
* @param options - Transport configuration
|
|
215
|
+
* @returns A configured Streamable HTTP transport
|
|
216
|
+
*
|
|
217
|
+
* @example
|
|
218
|
+
* ```typescript
|
|
219
|
+
* const transport = createStreamableHttpTransport({ port: 3000, stateful: true });
|
|
220
|
+
* await transport.connect(server);
|
|
221
|
+
* ```
|
|
222
|
+
*/
|
|
223
|
+
export declare function createStreamableHttpTransport(options?: StreamableHttpTransportOptions): StreamableHttpTransport;
|
|
224
|
+
//# sourceMappingURL=StreamableHttpTransport.d.ts.map
|
|
@@ -0,0 +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,uBAAuB,CAAC;AAEtD,OAAO,EAAE,aAAa,EAAE,KAAK,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAE1E;;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;CACxB;AAgBD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,qBAAa,uBAAwB,SAAQ,aAAa;IACzD,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,CAAwC;IACzD,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;gBAEpC,OAAO,GAAE,8BAAmC;IAaxD;;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;IAelD;;OAEG;YACW,cAAc;IAoF5B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IASzB;;;;;;;;OAQG;YACW,cAAc;IAsF5B;;;;;;OAMG;IACH,OAAO,CAAC,aAAa;IAsErB;;;;OAIG;IACH,OAAO,CAAC,eAAe;IAmDvB;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAQ/B;;;;OAIG;YACW,gBAAgB;IAkB9B;;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;IACG,IAAI,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAuC3C;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,6BAA6B,CAC5C,OAAO,GAAE,8BAAmC,GAC1C,uBAAuB,CAEzB"}
|