tracelattice 1.3.2 → 1.3.4

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 (185) hide show
  1. package/README.md +25 -25
  2. package/dist/ServerConfig.d.ts +16 -23
  3. package/dist/ServerConfig.d.ts.map +1 -1
  4. package/dist/ServerConfig.js +12 -1
  5. package/dist/ServerConfig.js.map +1 -1
  6. package/dist/__tests__/core/HistoryManager.ownership.test.d.ts +2 -0
  7. package/dist/__tests__/core/HistoryManager.ownership.test.d.ts.map +1 -0
  8. package/dist/__tests__/core/SessionLock.test.d.ts +6 -0
  9. package/dist/__tests__/core/SessionLock.test.d.ts.map +1 -0
  10. package/dist/__tests__/core/SessionManager.test.d.ts +8 -0
  11. package/dist/__tests__/core/SessionManager.test.d.ts.map +1 -0
  12. package/dist/__tests__/core/ThoughtProcessor.toolAllowlist.test.d.ts +2 -0
  13. package/dist/__tests__/core/ThoughtProcessor.toolAllowlist.test.d.ts.map +1 -0
  14. package/dist/__tests__/eval/fixtures/scenarios.d.ts.map +1 -1
  15. package/dist/__tests__/helpers/factories.d.ts +20 -1
  16. package/dist/__tests__/helpers/factories.d.ts.map +1 -1
  17. package/dist/__tests__/sanitize.enforceJsonShape.test.d.ts +2 -0
  18. package/dist/__tests__/sanitize.enforceJsonShape.test.d.ts.map +1 -0
  19. package/dist/__tests__/transport-owner-context.test.d.ts +8 -0
  20. package/dist/__tests__/transport-owner-context.test.d.ts.map +1 -0
  21. package/dist/cache/DiscoveryCache.d.ts +1 -1
  22. package/dist/cache/DiscoveryCache.d.ts.map +1 -1
  23. package/dist/cache/DiscoveryCache.js.map +1 -1
  24. package/dist/cli.js +3602 -8
  25. package/dist/config/ConfigLoader.d.ts +9 -2
  26. package/dist/config/ConfigLoader.d.ts.map +1 -1
  27. package/dist/config/ConfigLoader.js +12 -5
  28. package/dist/config/ConfigLoader.js.map +1 -1
  29. package/dist/context/RequestContext.d.ts +26 -0
  30. package/dist/context/RequestContext.d.ts.map +1 -1
  31. package/dist/context/RequestContext.js +7 -1
  32. package/dist/context/RequestContext.js.map +1 -1
  33. package/dist/contracts/PersistenceBackend.d.ts.map +1 -0
  34. package/dist/contracts/features.d.ts +39 -0
  35. package/dist/contracts/features.d.ts.map +1 -0
  36. package/dist/contracts/features.js +15 -0
  37. package/dist/contracts/features.js.map +1 -0
  38. package/dist/contracts/ids.d.ts +58 -0
  39. package/dist/contracts/ids.d.ts.map +1 -0
  40. package/dist/contracts/ids.js +31 -0
  41. package/dist/contracts/ids.js.map +1 -0
  42. package/dist/contracts/interfaces.d.ts +48 -3
  43. package/dist/contracts/interfaces.d.ts.map +1 -1
  44. package/dist/contracts/strategy.d.ts +2 -2
  45. package/dist/contracts/strategy.d.ts.map +1 -1
  46. package/dist/contracts/suspension.d.ts +3 -2
  47. package/dist/contracts/suspension.d.ts.map +1 -1
  48. package/dist/contracts/transport.d.ts +25 -0
  49. package/dist/contracts/transport.d.ts.map +1 -0
  50. package/dist/core/HistoryManager.d.ts +15 -4
  51. package/dist/core/HistoryManager.d.ts.map +1 -1
  52. package/dist/core/HistoryManager.js +25 -14
  53. package/dist/core/HistoryManager.js.map +1 -1
  54. package/dist/core/IHistoryManager.d.ts +10 -0
  55. package/dist/core/IHistoryManager.d.ts.map +1 -1
  56. package/dist/core/IThoughtFormatter.d.ts +51 -0
  57. package/dist/core/IThoughtFormatter.d.ts.map +1 -0
  58. package/dist/core/IThoughtFormatter.js +1 -0
  59. package/dist/core/InputNormalizer.d.ts.map +1 -1
  60. package/dist/core/InputNormalizer.js +9 -5
  61. package/dist/core/InputNormalizer.js.map +1 -1
  62. package/dist/core/PersistenceBuffer.d.ts +1 -1
  63. package/dist/core/PersistenceBuffer.d.ts.map +1 -1
  64. package/dist/core/PersistenceBuffer.js.map +1 -1
  65. package/dist/core/SessionLock.d.ts +56 -0
  66. package/dist/core/SessionLock.d.ts.map +1 -0
  67. package/dist/core/SessionLock.js +43 -0
  68. package/dist/core/SessionLock.js.map +1 -0
  69. package/dist/core/SessionManager.d.ts +18 -3
  70. package/dist/core/SessionManager.d.ts.map +1 -1
  71. package/dist/core/SessionManager.js +34 -1
  72. package/dist/core/SessionManager.js.map +1 -1
  73. package/dist/core/ThoughtFormatter.d.ts +2 -1
  74. package/dist/core/ThoughtFormatter.d.ts.map +1 -1
  75. package/dist/core/ThoughtFormatter.js +3 -0
  76. package/dist/core/ThoughtFormatter.js.map +1 -1
  77. package/dist/core/ThoughtProcessor.d.ts +22 -3
  78. package/dist/core/ThoughtProcessor.d.ts.map +1 -1
  79. package/dist/core/ThoughtProcessor.js +41 -16
  80. package/dist/core/ThoughtProcessor.js.map +1 -1
  81. package/dist/core/compression/CompressionService.js +3 -3
  82. package/dist/core/compression/CompressionService.js.map +1 -1
  83. package/dist/core/compression/Summary.d.ts +4 -3
  84. package/dist/core/compression/Summary.d.ts.map +1 -1
  85. package/dist/core/graph/Edge.d.ts +11 -4
  86. package/dist/core/graph/Edge.d.ts.map +1 -1
  87. package/dist/core/graph/EdgeEmitter.js +5 -5
  88. package/dist/core/graph/EdgeEmitter.js.map +1 -1
  89. package/dist/core/reasoning/strategies/StrategyFactory.d.ts +1 -1
  90. package/dist/core/reasoning/strategies/StrategyFactory.d.ts.map +1 -1
  91. package/dist/core/reasoning/strategies/StrategyFactory.js.map +1 -1
  92. package/dist/core/reasoning/strategies/TreeOfThoughtStrategy.d.ts.map +1 -1
  93. package/dist/core/reasoning/strategies/TreeOfThoughtStrategy.js +5 -0
  94. package/dist/core/reasoning/strategies/TreeOfThoughtStrategy.js.map +1 -1
  95. package/dist/core/reasoning.d.ts +8 -1
  96. package/dist/core/reasoning.d.ts.map +1 -1
  97. package/dist/core/step.d.ts +5 -0
  98. package/dist/core/step.d.ts.map +1 -1
  99. package/dist/core/thought.d.ts +4 -3
  100. package/dist/core/thought.d.ts.map +1 -1
  101. package/dist/core/tools/InMemorySuspensionStore.d.ts +3 -1
  102. package/dist/core/tools/InMemorySuspensionStore.d.ts.map +1 -1
  103. package/dist/core/tools/InMemorySuspensionStore.js +2 -2
  104. package/dist/core/tools/InMemorySuspensionStore.js.map +1 -1
  105. package/dist/di/Container.d.ts +6 -3
  106. package/dist/di/Container.d.ts.map +1 -1
  107. package/dist/di/Container.js.map +1 -1
  108. package/dist/di/ServiceRegistry.d.ts +6 -6
  109. package/dist/di/ServiceRegistry.d.ts.map +1 -1
  110. package/dist/errors.d.ts +84 -2
  111. package/dist/errors.d.ts.map +1 -1
  112. package/dist/errors.js +85 -22
  113. package/dist/errors.js.map +1 -1
  114. package/dist/health/HealthChecker.d.ts +1 -1
  115. package/dist/health/HealthChecker.d.ts.map +1 -1
  116. package/dist/health/HealthChecker.js.map +1 -1
  117. package/dist/lib.d.ts +60 -2
  118. package/dist/lib.d.ts.map +1 -1
  119. package/dist/lib.js +9 -3
  120. package/dist/lib.js.map +1 -1
  121. package/dist/persistence/FilePersistence.d.ts +2 -2
  122. package/dist/persistence/FilePersistence.d.ts.map +1 -1
  123. package/dist/persistence/FilePersistence.js.map +1 -1
  124. package/dist/persistence/MemoryPersistence.d.ts +1 -1
  125. package/dist/persistence/MemoryPersistence.d.ts.map +1 -1
  126. package/dist/persistence/MemoryPersistence.js.map +1 -1
  127. package/dist/persistence/PersistenceFactory.d.ts +1 -1
  128. package/dist/persistence/PersistenceFactory.d.ts.map +1 -1
  129. package/dist/persistence/PersistenceFactory.js.map +1 -1
  130. package/dist/persistence/SqlitePersistence.d.ts +1 -1
  131. package/dist/persistence/SqlitePersistence.d.ts.map +1 -1
  132. package/dist/persistence/SqlitePersistence.js.map +1 -1
  133. package/dist/pool/ConnectionPool.d.ts +11 -13
  134. package/dist/pool/ConnectionPool.d.ts.map +1 -1
  135. package/dist/pool/ConnectionPool.js.map +1 -1
  136. package/dist/pool/IConnectionPool.d.ts +100 -0
  137. package/dist/pool/IConnectionPool.d.ts.map +1 -0
  138. package/dist/pool/IConnectionPool.js +1 -0
  139. package/dist/registry/BaseRegistry.d.ts +1 -1
  140. package/dist/registry/BaseRegistry.d.ts.map +1 -1
  141. package/dist/registry/BaseRegistry.js.map +1 -1
  142. package/dist/registry/ToolRegistry.d.ts +1 -0
  143. package/dist/registry/ToolRegistry.d.ts.map +1 -1
  144. package/dist/registry/ToolRegistry.js +3 -0
  145. package/dist/registry/ToolRegistry.js.map +1 -1
  146. package/dist/sanitize.d.ts +70 -0
  147. package/dist/sanitize.d.ts.map +1 -1
  148. package/dist/sanitize.js +77 -1
  149. package/dist/sanitize.js.map +1 -1
  150. package/dist/schema.d.ts +35 -35
  151. package/dist/schema.d.ts.map +1 -1
  152. package/dist/schema.js +15 -5
  153. package/dist/schema.js.map +1 -1
  154. package/dist/transport/BaseTransport.d.ts +3 -2
  155. package/dist/transport/BaseTransport.d.ts.map +1 -1
  156. package/dist/transport/BaseTransport.js +1 -1
  157. package/dist/transport/BaseTransport.js.map +1 -1
  158. package/dist/transport/HttpTransport.d.ts +4 -2
  159. package/dist/transport/HttpTransport.d.ts.map +1 -1
  160. package/dist/transport/HttpTransport.js +13 -4
  161. package/dist/transport/HttpTransport.js.map +1 -1
  162. package/dist/transport/SseTransport.d.ts +4 -2
  163. package/dist/transport/SseTransport.d.ts.map +1 -1
  164. package/dist/transport/SseTransport.js +13 -3
  165. package/dist/transport/SseTransport.js.map +1 -1
  166. package/dist/transport/StreamableHttpTransport.d.ts +4 -2
  167. package/dist/transport/StreamableHttpTransport.d.ts.map +1 -1
  168. package/dist/transport/StreamableHttpTransport.js +12 -4
  169. package/dist/transport/StreamableHttpTransport.js.map +1 -1
  170. package/dist/types/skill.d.ts +5 -0
  171. package/dist/types/skill.d.ts.map +1 -1
  172. package/dist/types/tool.d.ts +6 -1
  173. package/dist/types/tool.d.ts.map +1 -1
  174. package/package.json +12 -11
  175. package/dist/__tests__/helpers/index.d.ts +0 -3
  176. package/dist/__tests__/helpers/index.d.ts.map +0 -1
  177. package/dist/contracts/index.d.ts +0 -14
  178. package/dist/contracts/index.d.ts.map +0 -1
  179. package/dist/index.d.ts +0 -2
  180. package/dist/index.d.ts.map +0 -1
  181. package/dist/index.js +0 -1
  182. package/dist/persistence/PersistenceBackend.d.ts.map +0 -1
  183. /package/dist/{persistence → contracts}/PersistenceBackend.d.ts +0 -0
  184. /package/dist/{persistence → contracts}/PersistenceBackend.js +0 -0
  185. /package/dist/contracts/{index.js → transport.js} +0 -0
package/dist/cli.js CHANGED
@@ -1,5 +1,1169 @@
1
1
  #!/usr/bin/env bun
2
- import*as e from"./lib.js";import*as t from"node:crypto";import*as s from"node:http";import*as i from"node:url";import*as n from"valibot";import{ValibotJsonSchemaAdapter as o}from"@tmcp/adapter-valibot";import{StdioTransport as r}from"@tmcp/transport-stdio";import{readFileSync as a}from"node:fs";import{dirname as l,join as c}from"node:path";import{McpServer as h}from"tmcp";import{AsyncLocalStorage as p}from"node:async_hooks";var d={787(e,t,s){s.d(t,{Ag:()=>o,m_:()=>a,qA:()=>n,u1:()=>l,yM:()=>r});class i extends Error{code;constructor(e,t){super(e),this.code=t,this.name="SequentialThinkingError",Error.captureStackTrace(this,this.constructor)}}class n extends i{constructor(e){super(`Session '${e}' is not active`,"SESSION_NOT_ACTIVE"),this.name="SessionNotActiveError"}}class o extends i{constructor(e){super(`Session not found: ${e}`,"SESSION_NOT_FOUND"),this.name="SessionNotFoundError"}}class r extends i{constructor(e){super(`Max sessions (${e}) reached. Wait for a session to close or increase maxSessions.`,"MAX_SESSIONS_REACHED"),this.name="MaxSessionsReachedError"}}class a extends i{constructor(){super("ConnectionPool has been terminated","POOL_TERMINATED"),this.name="PoolTerminatedError"}}function l(e){return e instanceof Error?e.message:String(e)}},527(e,t,s){s.d(t,{createConnectionPool:()=>r});var i=s(787);class n{_server;_id;_createdAt;_lastActivityAt;_isActiveValue;_timeout;_cleanupTimer=null;_logger;constructor(e,t,s,i){this._server=t,this._id=e,this._createdAt=Date.now(),this._lastActivityAt=this._createdAt,this._isActiveValue=!0,this._timeout=s,this._logger=i,this._startTimeout()}get isActive(){return this._isActiveValue}async process(e){if(!this.isActive)throw new i.qA(this._id);return this._lastActivityAt=Date.now(),this._resetTimeout(),this._server.processThought(e)}getInfo(){return{id:this._id,server:this._server,createdAt:this._createdAt,lastActivityAt:this._lastActivityAt,isActive:this.isActive}}isTimedOut(){return Date.now()-this._lastActivityAt>this._timeout}async close(){this._isActiveValue=!1,this._cleanupTimer&&(clearTimeout(this._cleanupTimer),this._cleanupTimer=null),this._server.stop()}_startTimeout(){this._cleanupTimer&&clearTimeout(this._cleanupTimer),this._cleanupTimer=setTimeout(()=>{this.isTimedOut()&&(this._logger.warn(`Session ${this._id} timed out, closing`),this.close().catch(e=>{this._logger.error(`Error closing timed out session ${this._id}:`,e)}))},this._timeout)}_resetTimeout(){this._startTimeout()}}class o{_sessions=new Map;_createSessionLock=null;_maxSessions;_sessionTimeout;_autoCleanup;_cleanupInterval;_cleanupTimerId=null;_terminated=!1;_logger;_serverFactory;constructor(e={}){this._maxSessions=e.maxSessions??100,this._sessionTimeout=e.sessionTimeout??3e5,this._autoCleanup=e.autoCleanup??!0,this._cleanupInterval=e.cleanupInterval??6e4,this._serverFactory=e.serverFactory??null,this._logger=e.logger??this._createNoopLogger(),this._autoCleanup&&this._startCleanup()}_createNoopLogger(){return{info:()=>{},warn:()=>{},error:()=>{},debug:()=>{},setLevel:()=>{},getLevel:()=>"info"}}async createSession(){let e;for(;this._createSessionLock;)await this._createSessionLock;if(this._terminated)throw new i.m_;if(this._sessions.size>=this._maxSessions)throw new i.yM(this._maxSessions);if(!this._serverFactory)throw Error("ConnectionPool requires a serverFactory option to create sessions");this._createSessionLock=new Promise(t=>{e=t});try{let e=`session_${Date.now()}_${Math.random().toString(36).substring(2,11)}`,t=await this._serverFactory(),s=new n(e,t,this._sessionTimeout,this._logger);return this._sessions.set(e,s),this._logger.info(`Created session ${e} (${this._sessions.size}/${this._maxSessions} active sessions)`),e}finally{e(),this._createSessionLock=null}}async process(e,t){let s=this._sessions.get(e);if(!s)throw new i.Ag(e);return s.process(t)}async closeSession(e){let t=this._sessions.get(e);if(!t)throw new i.Ag(e);await t.close(),this._sessions.delete(e),this._logger.info(`Closed session ${e} (${this._sessions.size}/${this._maxSessions} active sessions)`)}getSessionInfo(e){var t;return null==(t=this._sessions.get(e))?void 0:t.getInfo()}getActiveSessions(){return Array.from(this._sessions.values()).filter(e=>e.isActive).map(e=>e.getInfo())}getStats(){let e=this.getActiveSessions();return{totalSessions:this._sessions.size,activeSessions:e.length,maxSessions:this._maxSessions,cleanupEnabled:this._autoCleanup,sessionTimeout:this._sessionTimeout}}_startCleanup(){null!==this._cleanupTimerId&&clearInterval(this._cleanupTimerId),this._cleanupTimerId=setInterval(()=>{this._cleanupTimedOutSessions()},this._cleanupInterval)}_cleanupTimedOutSessions(){let e=0;for(let[t,s]of this._sessions.entries())s.isTimedOut()&&(s.close().catch(e=>{this._logger.error(`Error closing timed out session ${t}:`,e)}),this._sessions.delete(t),e++);e>0&&this._logger.info(`Cleaned ${e} timed-out sessions (${this._sessions.size}/${this._maxSessions} active sessions)`)}async terminate(){if(this._terminated)return;this._terminated=!0,null!==this._cleanupTimerId&&(clearInterval(this._cleanupTimerId),this._cleanupTimerId=null);let e=Array.from(this._sessions.values()).map(e=>e.close().catch(t=>{this._logger.error(`Error closing session ${e.getInfo().id}:`,t)}));await Promise.all(e),this._sessions.clear(),this._logger.info("ConnectionPool terminated")}async dispose(){await this.terminate()}isRunning(){return!this._terminated}}function r(e){return new o(e)}},555(e,t,s){s.d(t,{Uv:()=>d,ZK:()=>h,iV:()=>p});var i=s(821);let n=`A detailed tool for dynamic and reflective problem-solving through thoughts.
2
+ import * as __rspack_external__lib_js_262c9725 from "./lib.js";
3
+ import * as __rspack_external_node_crypto_9ba42079 from "node:crypto";
4
+ import * as __rspack_external_node_http_2dc67212 from "node:http";
5
+ import * as __rspack_external_node_url_e96de089 from "node:url";
6
+ import * as __rspack_external_valibot from "valibot";
7
+ import * as __rspack_external_node_async_hooks_e65a2d6c from "node:async_hooks";
8
+ import * as __rspack_external__tmcp_adapter_valibot_fbccc1df from "@tmcp/adapter-valibot";
9
+ import * as __rspack_external__tmcp_transport_stdio_9731848f from "@tmcp/transport-stdio";
10
+ import * as __rspack_external_node_fs_5ea92f0c from "node:fs";
11
+ import * as __rspack_external_node_path_c5b9b54f from "node:path";
12
+ import * as __rspack_external_tmcp from "tmcp";
13
+ var __webpack_modules__ = ({
14
+ 923(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
15
+
16
+ // EXPORTS
17
+ __webpack_require__.d(__webpack_exports__, {
18
+ RE: () => (/* binding */ getRequestId),
19
+ Vo: () => (/* binding */ runWithContext)
20
+ });
21
+
22
+ // UNUSED EXPORTS: getOwner
23
+
24
+ ;// CONCATENATED MODULE: external "node:async_hooks"
25
+
26
+ ;// CONCATENATED MODULE: ./src/context/RequestContext.ts
27
+ /**
28
+ * Request context management using AsyncLocalStorage for correlation IDs.
29
+ *
30
+ * Provides zero-cost request ID propagation across async boundaries
31
+ * via Node.js AsyncLocalStorage.
32
+ *
33
+ * @module context
34
+ */
35
+ /**
36
+ * AsyncLocalStorage instance for request context.
37
+ * Stores requestId that propagates across async boundaries.
38
+ */ const store = new __rspack_external_node_async_hooks_e65a2d6c.AsyncLocalStorage();
39
+ /**
40
+ * Get the current request ID from context.
41
+ *
42
+ * Returns undefined if called outside of a runWithContext() call.
43
+ *
44
+ * @returns The current request ID or undefined
45
+ */ function getRequestId() {
46
+ return store.getStore()?.requestId;
47
+ }
48
+ /**
49
+ * Run a function with the given request context. The context propagates
50
+ * across async boundaries via AsyncLocalStorage.
51
+ *
52
+ * @param ctx - Request context to install (requestId, optional owner)
53
+ * @param fn - Function to execute within the context
54
+ * @returns The return value of `fn`
55
+ */ function runWithContext(ctx, fn) {
56
+ return store.run(ctx, fn);
57
+ }
58
+ /**
59
+ * Get the current owner identifier from context.
60
+ *
61
+ * Returns undefined when called outside of a runWithContext() call or when
62
+ * the context did not specify an owner (e.g. stdio transport).
63
+ *
64
+ * @returns The current owner or undefined
65
+ */ function getOwner() {
66
+ return store.getStore()?.owner;
67
+ }
68
+
69
+
70
+ },
71
+ 937(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
72
+ __webpack_require__.d(__webpack_exports__, {
73
+ Ag: () => (SessionNotFoundError),
74
+ m_: () => (PoolTerminatedError),
75
+ qA: () => (SessionNotActiveError),
76
+ u1: () => (getErrorMessage),
77
+ yM: () => (MaxSessionsReachedError)
78
+ });
79
+ /**
80
+ * Custom error types for the TraceLattice server.
81
+ *
82
+ * This module defines a hierarchy of error classes for handling various
83
+ * error conditions that can occur in the sequential thinking server.
84
+ * All errors extend the base `SequentialThinkingError` class with
85
+ * specific error codes for programmatic handling.
86
+ *
87
+ * @example
88
+ * ```typescript
89
+ * import { ToolNotFoundError, SkillDiscoveryError } from './errors.js';
90
+ *
91
+ * // Throw a tool not found error
92
+ * throw new ToolNotFoundError('my-tool');
93
+ *
94
+ * // Catch and handle specific errors
95
+ * try {
96
+ * await discoverSkills(dir);
97
+ * } catch (error) {
98
+ * if (error instanceof SkillDiscoveryError) {
99
+ * console.error(`Failed to discover skills: ${error.message}`);
100
+ * console.error(`Error code: ${error.code}`);
101
+ * }
102
+ * }
103
+ * ```
104
+ * @module errors
105
+ */ /**
106
+ * All known error codes as a const object for exhaustive switching.
107
+ */ const ERROR_CODES = {
108
+ CONFIGURATION_ERROR: 'CONFIGURATION_ERROR',
109
+ TOOL_NOT_FOUND: 'TOOL_NOT_FOUND',
110
+ SKILL_NOT_FOUND: 'SKILL_NOT_FOUND',
111
+ INVALID_THOUGHT: 'INVALID_THOUGHT',
112
+ SKILL_DISCOVERY_FAILED: 'SKILL_DISCOVERY_FAILED',
113
+ HISTORY_LIMIT_EXCEEDED: 'HISTORY_LIMIT_EXCEEDED',
114
+ DUPLICATE_SKILL: 'DUPLICATE_SKILL',
115
+ INVALID_SKILL: 'INVALID_SKILL',
116
+ DUPLICATE_TOOL: 'DUPLICATE_TOOL',
117
+ INVALID_TOOL: 'INVALID_TOOL',
118
+ SESSION_NOT_ACTIVE: 'SESSION_NOT_ACTIVE',
119
+ SESSION_NOT_FOUND: 'SESSION_NOT_FOUND',
120
+ MAX_SESSIONS_REACHED: 'MAX_SESSIONS_REACHED',
121
+ POOL_TERMINATED: 'POOL_TERMINATED',
122
+ VALIDATION_ERROR: 'VALIDATION_ERROR',
123
+ INVALID_EDGE: 'INVALID_EDGE',
124
+ CYCLE_DETECTED: 'CYCLE_DETECTED',
125
+ SUSPENSION_NOT_FOUND: 'SUSPENSION_NOT_FOUND',
126
+ SUSPENSION_EXPIRED: 'SUSPENSION_EXPIRED',
127
+ INVALID_TOOL_CALL: 'INVALID_TOOL_CALL',
128
+ INVALID_BACKTRACK: 'INVALID_BACKTRACK',
129
+ DUPLICATE_SUMMARY: 'DUPLICATE_SUMMARY',
130
+ UNKNOWN_TOOL: 'UNKNOWN_TOOL',
131
+ LOCK_TIMEOUT: 'LOCK_TIMEOUT',
132
+ SESSION_ACCESS_DENIED: 'SESSION_ACCESS_DENIED'
133
+ };
134
+ /**
135
+ * All known warning codes as a const object.
136
+ * Warnings are non-fatal advisory signals returned alongside successful results.
137
+ */ const WARNING_CODES = (/* unused pure expression or super */ null && ({
138
+ TOTAL_THOUGHTS_ADJUSTED: 'TOTAL_THOUGHTS_ADJUSTED'
139
+ }));
140
+ /**
141
+ * Base error class for all Sequential Thinking server errors.
142
+ *
143
+ * This error extends the native `Error` class and adds a `code` property
144
+ * for programmatic error identification and handling. All specific error
145
+ * types in the system extend this base class.
146
+ *
147
+ * @remarks
148
+ * **Error Codes:**
149
+ * - `TOOL_NOT_FOUND` - A requested tool was not found
150
+ * - `SKILL_NOT_FOUND` - A requested skill was not found
151
+ * - `INVALID_THOUGHT` - Thought validation failed
152
+ * - `SKILL_DISCOVERY_FAILED` - Skill discovery operation failed
153
+ * - `HISTORY_LIMIT_EXCEEDED` - History size limit was exceeded
154
+ * - `INVALID_EDGE` - An invalid edge operation was attempted
155
+ *
156
+ * @example
157
+ * ```typescript
158
+ * // Throw a custom sequential thinking error
159
+ * throw new SequentialThinkingError('Custom error message', 'CUSTOM_CODE');
160
+ *
161
+ * // Check if an error is a SequentialThinkingError
162
+ * if (error instanceof SequentialThinkingError) {
163
+ * console.error(`Error [${error.code}]: ${error.message}`);
164
+ * }
165
+ * ```
166
+ */ class SequentialThinkingError extends Error {
167
+ /** The error code for programmatic identification. */ code;
168
+ /**
169
+ * Creates a new SequentialThinkingError.
170
+ *
171
+ * @param message - Human-readable error message
172
+ * @param code - Error code for programmatic handling
173
+ *
174
+ * @example
175
+ * ```typescript
176
+ * const error = new SequentialThinkingError(
177
+ * 'Something went wrong',
178
+ * 'CUSTOM_ERROR'
179
+ * );
180
+ * console.log(error.code); // 'CUSTOM_ERROR'
181
+ * ```
182
+ */ constructor(message, code){
183
+ super(message);
184
+ this.code = code;
185
+ this.name = 'SequentialThinkingError';
186
+ Error.captureStackTrace(this, this.constructor);
187
+ }
188
+ }
189
+ class ConfigurationError extends SequentialThinkingError {
190
+ constructor(message){
191
+ super(message, ERROR_CODES.CONFIGURATION_ERROR);
192
+ this.name = 'ConfigurationError';
193
+ }
194
+ }
195
+ /**
196
+ * Error thrown when a requested tool is not found in the registry.
197
+ *
198
+ * This error is thrown when attempting to retrieve, update, or delete
199
+ * a tool that doesn't exist in the tool registry.
200
+ *
201
+ * @example
202
+ * ```typescript
203
+ * const tool = registry.getTool('non-existent-tool');
204
+ * if (!tool) {
205
+ * throw new ToolNotFoundError('non-existent-tool');
206
+ * }
207
+ * ```
208
+ */ class ToolNotFoundError extends SequentialThinkingError {
209
+ /**
210
+ * Creates a new ToolNotFoundError.
211
+ *
212
+ * @param toolName - The name of the tool that was not found
213
+ * @param action - Optional action being performed (e.g., 'remove', 'update')
214
+ *
215
+ * @example
216
+ * ```typescript
217
+ * throw new ToolNotFoundError('my-custom-tool');
218
+ * // Error: tool 'my-custom-tool' not found
219
+ *
220
+ * throw new ToolNotFoundError('my-custom-tool', 'remove');
221
+ * // Error: tool 'my-custom-tool' not found, cannot remove
222
+ * // Code: TOOL_NOT_FOUND
223
+ * ```
224
+ */ constructor(toolName, action){
225
+ const message = action ? `Tool '${toolName}' not found, cannot ${action}` : `Tool '${toolName}' not found`;
226
+ super(message, ERROR_CODES.TOOL_NOT_FOUND);
227
+ this.name = 'ToolNotFoundError';
228
+ }
229
+ }
230
+ /**
231
+ * Error thrown when a requested skill is not found in the registry.
232
+ *
233
+ * This error is thrown when attempting to retrieve, update, or delete
234
+ * a skill that doesn't exist in the skill registry.
235
+ *
236
+ * @example
237
+ * ```typescript
238
+ * const skill = registry.getSkill('non-existent-skill');
239
+ * if (!skill) {
240
+ * throw new SkillNotFoundError('non-existent-skill');
241
+ * }
242
+ * ```
243
+ */ class SkillNotFoundError extends SequentialThinkingError {
244
+ /**
245
+ * Creates a new SkillNotFoundError.
246
+ *
247
+ * @param skillName - The name of the skill that was not found
248
+ * @param action - Optional action being performed (e.g., 'remove', 'update')
249
+ *
250
+ * @example
251
+ * ```typescript
252
+ * throw new SkillNotFoundError('my-custom-skill');
253
+ * // Error: skill 'my-custom-skill' not found
254
+ *
255
+ * throw new SkillNotFoundError('my-custom-skill', 'remove');
256
+ * // Error: skill 'my-custom-skill' not found, cannot remove
257
+ * // Code: SKILL_NOT_FOUND
258
+ * ```
259
+ */ constructor(skillName, action){
260
+ const message = action ? `Skill '${skillName}' not found, cannot ${action}` : `Skill '${skillName}' not found`;
261
+ super(message, ERROR_CODES.SKILL_NOT_FOUND);
262
+ this.name = 'SkillNotFoundError';
263
+ }
264
+ }
265
+ /**
266
+ * Error thrown when thought validation fails.
267
+ *
268
+ * This error is thrown when a thought fails validation, typically due to
269
+ * invalid values, missing required fields, or constraint violations.
270
+ *
271
+ * @example
272
+ * ```typescript
273
+ * // Validate thought number
274
+ * if (thought.thought_number < 1) {
275
+ * throw new InvalidThoughtError(thought.thought_number, 'thought_number must be >= 1');
276
+ * }
277
+ * ```
278
+ */ class InvalidThoughtError extends SequentialThinkingError {
279
+ /**
280
+ * Creates a new InvalidThoughtError.
281
+ *
282
+ * @param thoughtNumber - The thought number that failed validation
283
+ * @param reason - Human-readable explanation of why validation failed
284
+ *
285
+ * @example
286
+ * ```typescript
287
+ * throw new InvalidThoughtError(5, 'thought_number exceeds total_thoughts');
288
+ * // Error: Invalid thought 5: thought_number exceeds total_thoughts
289
+ * // Code: INVALID_THOUGHT
290
+ * ```
291
+ */ constructor(thoughtNumber, reason){
292
+ super(`Invalid thought ${thoughtNumber}: ${reason}`, ERROR_CODES.INVALID_THOUGHT);
293
+ this.name = 'InvalidThoughtError';
294
+ }
295
+ }
296
+ /**
297
+ * Error thrown when skill discovery fails.
298
+ *
299
+ * This error is thrown when the skill discovery process encounters an issue,
300
+ * such as filesystem errors, invalid skill files, or parsing failures.
301
+ *
302
+ * @remarks
303
+ * The original error that caused the discovery failure is preserved in the
304
+ * `cause` property for debugging purposes.
305
+ *
306
+ * @example
307
+ * ```typescript
308
+ * try {
309
+ * await discoverSkills('./skills');
310
+ * } catch (error) {
311
+ * throw new SkillDiscoveryError('./skills', error as Error);
312
+ * }
313
+ * ```
314
+ */ class SkillDiscoveryError extends SequentialThinkingError {
315
+ /** The underlying error that caused the discovery failure. */ cause;
316
+ /**
317
+ * Creates a new SkillDiscoveryError.
318
+ *
319
+ * @param directory - The directory where discovery failed
320
+ * @param cause - The underlying error that caused the failure
321
+ *
322
+ * @example
323
+ * ```typescript
324
+ * try {
325
+ * const skills = await loadSkills('./invalid-directory');
326
+ * } catch (error) {
327
+ * throw new SkillDiscoveryError('./invalid-directory', error as Error);
328
+ * }
329
+ * ```
330
+ */ constructor(directory, cause){
331
+ super(`Failed to discover skills in ${directory}: ${cause.message}`, ERROR_CODES.SKILL_DISCOVERY_FAILED);
332
+ this.name = 'SkillDiscoveryError';
333
+ this.cause = cause;
334
+ }
335
+ }
336
+ /**
337
+ * Error thrown when history size exceeds the configured limit.
338
+ *
339
+ * This error is thrown when an operation would cause the history size
340
+ * to exceed the maximum configured size limit.
341
+ *
342
+ * @example
343
+ * ```typescript
344
+ * if (history.length >= maxSize) {
345
+ * throw new HistoryLimitExceededError(history.length, maxSize);
346
+ * }
347
+ * ```
348
+ */ class HistoryLimitExceededError extends SequentialThinkingError {
349
+ /**
350
+ * Creates a new HistoryLimitExceededError.
351
+ *
352
+ * @param currentSize - The current history size
353
+ * @param maxSize - The maximum allowed size
354
+ *
355
+ * @example
356
+ * ```typescript
357
+ * throw new HistoryLimitExceededError(1500, 1000);
358
+ * // Error: History size 1500 exceeds limit 1000
359
+ * // Code: HISTORY_LIMIT_EXCEEDED
360
+ * ```
361
+ */ constructor(currentSize, maxSize){
362
+ super(`History size ${currentSize} exceeds limit ${maxSize}`, ERROR_CODES.HISTORY_LIMIT_EXCEEDED);
363
+ this.name = 'HistoryLimitExceededError';
364
+ }
365
+ }
366
+ /**
367
+ * Error thrown when attempting to add a skill that already exists.
368
+ *
369
+ * This error is thrown when trying to register a skill with a name that
370
+ * is already present in the skill registry.
371
+ *
372
+ * @example
373
+ * ```typescript
374
+ * if (registry.hasSkill(skill.name)) {
375
+ * throw new DuplicateSkillError(skill.name);
376
+ * }
377
+ * ```
378
+ */ class DuplicateSkillError extends SequentialThinkingError {
379
+ /**
380
+ * Creates a new DuplicateSkillError.
381
+ *
382
+ * @param skillName - The name of the duplicate skill
383
+ *
384
+ * @example
385
+ * ```typescript
386
+ * throw new DuplicateSkillError('my-skill');
387
+ * // Error: skill 'my-skill' already exists
388
+ * // Code: DUPLICATE_SKILL
389
+ * ```
390
+ */ constructor(skillName){
391
+ super(`skill '${skillName}' already exists`, ERROR_CODES.DUPLICATE_SKILL);
392
+ this.name = 'DuplicateSkillError';
393
+ }
394
+ }
395
+ /**
396
+ * Error thrown when a skill has invalid data.
397
+ *
398
+ * This error is thrown when a skill fails validation, typically due to
399
+ * missing required fields or invalid values.
400
+ *
401
+ * @example
402
+ * ```typescript
403
+ * if (!skill.name) {
404
+ * throw new InvalidSkillError('Skill must have a valid name');
405
+ * }
406
+ * ```
407
+ */ class InvalidSkillError extends SequentialThinkingError {
408
+ /**
409
+ * Creates a new InvalidSkillError.
410
+ *
411
+ * @param reason - The reason for the validation failure
412
+ *
413
+ * @example
414
+ * ```typescript
415
+ * throw new InvalidSkillError('Skill must have a valid name');
416
+ * // Error: Invalid skill: Skill must have a valid name
417
+ * // Code: INVALID_SKILL
418
+ * ```
419
+ */ constructor(reason){
420
+ super(`Invalid skill: ${reason}`, ERROR_CODES.INVALID_SKILL);
421
+ this.name = 'InvalidSkillError';
422
+ }
423
+ }
424
+ /**
425
+ * Error thrown when attempting to add a tool that already exists.
426
+ *
427
+ * This error is thrown when trying to register a tool with a name that
428
+ * is already present in the tool registry.
429
+ *
430
+ * @example
431
+ * ```typescript
432
+ * if (registry.hasTool(tool.name)) {
433
+ * throw new DuplicateToolError(tool.name);
434
+ * }
435
+ * ```
436
+ */ class DuplicateToolError extends SequentialThinkingError {
437
+ /**
438
+ * Creates a new DuplicateToolError.
439
+ *
440
+ * @param toolName - The name of the duplicate tool
441
+ *
442
+ * @example
443
+ * ```typescript
444
+ * throw new DuplicateToolError('my-tool');
445
+ * // Error: tool 'my-tool' already exists
446
+ * // Code: DUPLICATE_TOOL
447
+ * ```
448
+ */ constructor(toolName){
449
+ super(`tool '${toolName}' already exists`, ERROR_CODES.DUPLICATE_TOOL);
450
+ this.name = 'DuplicateToolError';
451
+ }
452
+ }
453
+ /**
454
+ * Error thrown when a tool has invalid data.
455
+ *
456
+ * This error is thrown when a tool fails validation, typically due to
457
+ * missing required fields or invalid values.
458
+ *
459
+ * @example
460
+ * ```typescript
461
+ * if (!tool.name) {
462
+ * throw new InvalidToolError('Tool must have a valid name');
463
+ * }
464
+ * ```
465
+ */ class InvalidToolError extends SequentialThinkingError {
466
+ /**
467
+ * Creates a new InvalidToolError.
468
+ *
469
+ * @param reason - The reason for the validation failure
470
+ *
471
+ * @example
472
+ * ```typescript
473
+ * throw new InvalidToolError('Tool must have a valid name');
474
+ * // Error: Invalid tool: Tool must have a valid name
475
+ * // Code: INVALID_TOOL
476
+ * ```
477
+ */ constructor(reason){
478
+ super(`Invalid tool: ${reason}`, ERROR_CODES.INVALID_TOOL);
479
+ this.name = 'InvalidToolError';
480
+ }
481
+ }
482
+ /**
483
+ * Error thrown when attempting to process a session that is not active.
484
+ *
485
+ * This error is thrown when trying to use a session that has been closed
486
+ * or deactivated.
487
+ *
488
+ * @example
489
+ * ```typescript
490
+ * if (!session.isActive) {
491
+ * throw new SessionNotActiveError(sessionId);
492
+ * }
493
+ * ```
494
+ */ class SessionNotActiveError extends SequentialThinkingError {
495
+ /**
496
+ * Creates a new SessionNotActiveError.
497
+ *
498
+ * @param sessionId - The ID of the inactive session
499
+ *
500
+ * @example
501
+ * ```typescript
502
+ * throw new SessionNotActiveError('session-123');
503
+ * // Error: Session 'session-123' is not active
504
+ * // Code: SESSION_NOT_ACTIVE
505
+ * ```
506
+ */ constructor(sessionId){
507
+ super(`Session '${sessionId}' is not active`, ERROR_CODES.SESSION_NOT_ACTIVE);
508
+ this.name = 'SessionNotActiveError';
509
+ }
510
+ }
511
+ /**
512
+ * Error thrown when a requested session is not found in the pool.
513
+ *
514
+ * This error is thrown when attempting to retrieve, process, or close
515
+ * a session that doesn't exist in the session pool.
516
+ *
517
+ * @example
518
+ * ```typescript
519
+ * const session = pool.getSession('non-existent-session');
520
+ * if (!session) {
521
+ * throw new SessionNotFoundError('non-existent-session');
522
+ * }
523
+ * ```
524
+ */ class SessionNotFoundError extends SequentialThinkingError {
525
+ /**
526
+ * Creates a new SessionNotFoundError.
527
+ *
528
+ * @param sessionId - The ID of the session that was not found
529
+ *
530
+ * @example
531
+ * ```typescript
532
+ * throw new SessionNotFoundError('session-123');
533
+ * // Error: Session not found: session-123
534
+ * // Code: SESSION_NOT_FOUND
535
+ * ```
536
+ */ constructor(sessionId){
537
+ super(`Session not found: ${sessionId}`, ERROR_CODES.SESSION_NOT_FOUND);
538
+ this.name = 'SessionNotFoundError';
539
+ }
540
+ }
541
+ /**
542
+ * Error thrown when the maximum number of sessions has been reached.
543
+ *
544
+ * This error is thrown when trying to create a new session when the
545
+ * pool has reached its configured maximum session limit.
546
+ *
547
+ * @example
548
+ * ```typescript
549
+ * if (pool.sessionCount >= pool.maxSessions) {
550
+ * throw new MaxSessionsReachedError(pool.maxSessions);
551
+ * }
552
+ * ```
553
+ */ class MaxSessionsReachedError extends SequentialThinkingError {
554
+ /**
555
+ * Creates a new MaxSessionsReachedError.
556
+ *
557
+ * @param maxSessions - The maximum number of sessions allowed
558
+ *
559
+ * @example
560
+ * ```typescript
561
+ * throw new MaxSessionsReachedError(100);
562
+ * // Error: Max sessions (100) reached. Wait for a session to close or increase maxSessions.
563
+ * // Code: MAX_SESSIONS_REACHED
564
+ * ```
565
+ */ constructor(maxSessions){
566
+ super(`Max sessions (${maxSessions}) reached. Wait for a session to close or increase maxSessions.`, ERROR_CODES.MAX_SESSIONS_REACHED);
567
+ this.name = 'MaxSessionsReachedError';
568
+ }
569
+ }
570
+ /**
571
+ * Error thrown when attempting to use a terminated connection pool.
572
+ *
573
+ * This error is thrown when trying to create sessions or process requests
574
+ * after the connection pool has been terminated.
575
+ *
576
+ * @example
577
+ * ```typescript
578
+ * if (pool.isTerminated) {
579
+ * throw new PoolTerminatedError();
580
+ * }
581
+ * ```
582
+ */ class PoolTerminatedError extends SequentialThinkingError {
583
+ /**
584
+ * Creates a new PoolTerminatedError.
585
+ *
586
+ * @example
587
+ * ```typescript
588
+ * throw new PoolTerminatedError();
589
+ * // Error: ConnectionPool has been terminated
590
+ * // Code: POOL_TERMINATED
591
+ * ```
592
+ */ constructor(){
593
+ super('ConnectionPool has been terminated', ERROR_CODES.POOL_TERMINATED);
594
+ this.name = 'PoolTerminatedError';
595
+ }
596
+ }
597
+ /**
598
+ * Error thrown when input validation fails due to invalid or malicious data.
599
+ *
600
+ * This error is thrown when user input fails security or format validation,
601
+ * such as path traversal attempts or invalid identifier formats.
602
+ *
603
+ * @example
604
+ * ```typescript
605
+ * if (!BRANCH_ID_PATTERN.test(branchId)) {
606
+ * throw new ValidationError('branchId', 'Invalid format');
607
+ * }
608
+ * ```
609
+ */ class ValidationError extends SequentialThinkingError {
610
+ /** The field that failed validation. */ field;
611
+ constructor(field, reason){
612
+ super(`Validation failed for '${field}': ${reason}`, ERROR_CODES.VALIDATION_ERROR);
613
+ this.name = 'ValidationError';
614
+ this.field = field;
615
+ }
616
+ }
617
+ /**
618
+ * Error thrown when an invalid edge operation is attempted.
619
+ *
620
+ * This error is thrown when attempting to add an edge that violates
621
+ * structural invariants of the thought DAG, such as a self-edge
622
+ * (where `from` and `to` reference the same thought).
623
+ *
624
+ * @example
625
+ * ```typescript
626
+ * if (edge.from === edge.to) {
627
+ * throw new InvalidEdgeError(
628
+ * `Self-edge not allowed: from and to are the same (${edge.from})`
629
+ * );
630
+ * }
631
+ * ```
632
+ */ class InvalidEdgeError extends SequentialThinkingError {
633
+ /**
634
+ * Creates a new InvalidEdgeError.
635
+ *
636
+ * @param message - Human-readable explanation of the invalid edge
637
+ *
638
+ * @example
639
+ * ```typescript
640
+ * throw new InvalidEdgeError('Self-edge not allowed: from and to are the same (t1)');
641
+ * // Code: INVALID_EDGE
642
+ * ```
643
+ */ constructor(message){
644
+ super(message, ERROR_CODES.INVALID_EDGE);
645
+ this.name = 'InvalidEdgeError';
646
+ }
647
+ }
648
+ /**
649
+ * Error thrown when a cycle is detected during graph traversal.
650
+ *
651
+ * This error is thrown by graph algorithms (such as topological sort)
652
+ * when the thought DAG contains a cycle, violating the acyclic invariant.
653
+ *
654
+ * @example
655
+ * ```typescript
656
+ * try {
657
+ * const order = graphView.topological(sessionId);
658
+ * } catch (error) {
659
+ * if (error instanceof CycleDetectedError) {
660
+ * console.error('Cycle in thought graph:', error.message);
661
+ * }
662
+ * }
663
+ * ```
664
+ */ class CycleDetectedError extends SequentialThinkingError {
665
+ /**
666
+ * Creates a new CycleDetectedError.
667
+ *
668
+ * @param message - Human-readable explanation of the cycle
669
+ *
670
+ * @example
671
+ * ```typescript
672
+ * throw new CycleDetectedError('Cycle detected in session s1');
673
+ * // Code: CYCLE_DETECTED
674
+ * ```
675
+ */ constructor(message){
676
+ super(message, ERROR_CODES.CYCLE_DETECTED);
677
+ this.name = 'CycleDetectedError';
678
+ }
679
+ }
680
+ /**
681
+ * Error thrown when a suspension record is not found.
682
+ *
683
+ * This error is thrown when attempting to resume a tool interleave
684
+ * suspension that does not exist in the suspension store.
685
+ */ class SuspensionNotFoundError extends SequentialThinkingError {
686
+ constructor(message){
687
+ super(message, ERROR_CODES.SUSPENSION_NOT_FOUND);
688
+ this.name = 'SuspensionNotFoundError';
689
+ }
690
+ }
691
+ /**
692
+ * Error thrown when a suspension record has expired.
693
+ *
694
+ * This error is thrown when attempting to resume a tool interleave
695
+ * suspension whose TTL has elapsed.
696
+ */ class SuspensionExpiredError extends SequentialThinkingError {
697
+ constructor(message){
698
+ super(message, ERROR_CODES.SUSPENSION_EXPIRED);
699
+ this.name = 'SuspensionExpiredError';
700
+ }
701
+ }
702
+ /**
703
+ * Error thrown when a tool call payload is invalid.
704
+ *
705
+ * This error is thrown when a tool interleave invocation has malformed
706
+ * arguments, missing identifiers, or otherwise fails validation.
707
+ */ class InvalidToolCallError extends SequentialThinkingError {
708
+ constructor(message){
709
+ super(message, ERROR_CODES.INVALID_TOOL_CALL);
710
+ this.name = 'InvalidToolCallError';
711
+ }
712
+ }
713
+ /**
714
+ * Error thrown when a backtrack operation is invalid.
715
+ *
716
+ * This error is thrown when an attempt to backtrack the reasoning
717
+ * chain references an unreachable thought or violates DAG invariants.
718
+ */ class InvalidBacktrackError extends SequentialThinkingError {
719
+ constructor(message){
720
+ super(message, ERROR_CODES.INVALID_BACKTRACK);
721
+ this.name = 'InvalidBacktrackError';
722
+ }
723
+ }
724
+ /**
725
+ * Error thrown when a tool_call references a tool not registered with the server.
726
+ *
727
+ * Acts as an allowlist gate: only tools registered in the ToolRegistry may be
728
+ * invoked through tool interleave. Prevents arbitrary tool name injection.
729
+ */ class UnknownToolError extends SequentialThinkingError {
730
+ toolName;
731
+ constructor(toolName, message){
732
+ super(message ?? `Unknown tool '${toolName}': not registered with the server`, ERROR_CODES.UNKNOWN_TOOL);
733
+ this.name = 'UnknownToolError';
734
+ this.toolName = toolName;
735
+ }
736
+ }
737
+ /**
738
+ * Error thrown when a per-session async lock cannot be acquired in time.
739
+ *
740
+ * Indicates that a critical section held the lock for longer than the
741
+ * configured timeout, suggesting a stuck handler or deadlock.
742
+ */ class LockTimeoutError extends SequentialThinkingError {
743
+ sessionId;
744
+ timeoutMs;
745
+ constructor(sessionId, timeoutMs){
746
+ super(`Lock timeout for session '${sessionId}' after ${timeoutMs}ms`, ERROR_CODES.LOCK_TIMEOUT);
747
+ this.name = 'LockTimeoutError';
748
+ this.sessionId = sessionId;
749
+ this.timeoutMs = timeoutMs;
750
+ }
751
+ }
752
+ /**
753
+ * Error thrown when a session is accessed by a non-owner.
754
+ *
755
+ * Sessions are bound to an owner identifier on first creation when accessed
756
+ * via a multi-user transport (SSE/HTTP). Subsequent access attempts using a
757
+ * different owner are rejected to prevent IDOR (Insecure Direct Object
758
+ * Reference) vulnerabilities.
759
+ *
760
+ * The stdio transport does not set an owner, so its sessions are unaffected.
761
+ */ class SessionAccessDeniedError extends SequentialThinkingError {
762
+ sessionId;
763
+ expectedOwner;
764
+ actualOwner;
765
+ constructor(sessionId, expectedOwner, actualOwner){
766
+ super(`Access denied to session '${sessionId}': owned by '${expectedOwner}', accessed by '${actualOwner ?? 'anonymous'}'`, ERROR_CODES.SESSION_ACCESS_DENIED);
767
+ this.name = 'SessionAccessDeniedError';
768
+ this.sessionId = sessionId;
769
+ this.expectedOwner = expectedOwner;
770
+ this.actualOwner = actualOwner;
771
+ }
772
+ }
773
+ /**
774
+ * Type guard to check if an error has a specific error code.
775
+ */ function isErrorCode(err, code) {
776
+ return err instanceof SequentialThinkingError && err.code === code;
777
+ }
778
+ /**
779
+ * Extract a human-readable message from an unknown error value.
780
+ *
781
+ * Standardizes the common `error instanceof Error ? error.message : String(error)`
782
+ * pattern used in catch blocks across the codebase.
783
+ *
784
+ * @param error - The unknown error value to extract a message from
785
+ * @returns The error message string
786
+ *
787
+ * @example
788
+ * ```typescript
789
+ * try {
790
+ * await doSomething();
791
+ * } catch (error) {
792
+ * logger.error('Failed', { error: getErrorMessage(error) });
793
+ * }
794
+ * ```
795
+ */ function getErrorMessage(error) {
796
+ return error instanceof Error ? error.message : String(error);
797
+ }
798
+
799
+
800
+ },
801
+ 789(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
802
+ __webpack_require__.d(__webpack_exports__, {
803
+ createConnectionPool: () => (createConnectionPool)
804
+ });
805
+ /* import */ var _errors_js__rspack_import_0 = __webpack_require__(937);
806
+ /**
807
+ * Connection Pool for managing concurrent user sessions.
808
+ *
809
+ * This module provides session management for multi-user scenarios,
810
+ * allowing multiple concurrent clients to each have isolated state.
811
+ *
812
+ * @example
813
+ * ```typescript
814
+ * const pool = new ConnectionPool({
815
+ * maxSessions: 100,
816
+ * sessionTimeout: 300000 // 5 minutes
817
+ * });
818
+ *
819
+ * const sessionId = await pool.createSession();
820
+ * await pool.process(sessionId, thought);
821
+ * await pool.closeSession(sessionId);
822
+ * ```
823
+ */
824
+ /**
825
+ * Represents a user session with its own server instance.
826
+ */ class Session {
827
+ _server;
828
+ _id;
829
+ _createdAt;
830
+ _lastActivityAt;
831
+ _isActiveValue;
832
+ _timeout;
833
+ _cleanupTimer = null;
834
+ _logger;
835
+ constructor(id, server, timeout, logger){
836
+ this._server = server;
837
+ this._id = id;
838
+ this._createdAt = Date.now();
839
+ this._lastActivityAt = this._createdAt;
840
+ this._isActiveValue = true;
841
+ this._timeout = timeout;
842
+ this._logger = logger;
843
+ // Start session timeout timer
844
+ this._startTimeout();
845
+ }
846
+ /**
847
+ * Check if the session is active.
848
+ */ get isActive() {
849
+ return this._isActiveValue;
850
+ }
851
+ /**
852
+ * Process a thought through this session's server instance.
853
+ */ async process(input) {
854
+ if (!this.isActive) {
855
+ throw new _errors_js__rspack_import_0/* .SessionNotActiveError */.qA(this._id);
856
+ }
857
+ // Update last activity
858
+ this._lastActivityAt = Date.now();
859
+ // Reset timeout timer
860
+ this._resetTimeout();
861
+ // Process the thought
862
+ return this._server.processThought(input);
863
+ }
864
+ /**
865
+ * Get session information.
866
+ */ getInfo() {
867
+ return {
868
+ id: this._id,
869
+ server: this._server,
870
+ createdAt: this._createdAt,
871
+ lastActivityAt: this._lastActivityAt,
872
+ isActive: this.isActive
873
+ };
874
+ }
875
+ /**
876
+ * Check if the session has timed out.
877
+ */ isTimedOut() {
878
+ return Date.now() - this._lastActivityAt > this._timeout;
879
+ }
880
+ /**
881
+ * Close the session and stop the server.
882
+ */ async close() {
883
+ this._isActiveValue = false;
884
+ // Stop timeout timer
885
+ if (this._cleanupTimer) {
886
+ clearTimeout(this._cleanupTimer);
887
+ this._cleanupTimer = null;
888
+ }
889
+ // Stop the server
890
+ this._server.stop();
891
+ }
892
+ /**
893
+ * Start the session timeout timer.
894
+ */ _startTimeout() {
895
+ if (this._cleanupTimer) {
896
+ clearTimeout(this._cleanupTimer);
897
+ }
898
+ this._cleanupTimer = setTimeout(()=>{
899
+ if (this.isTimedOut()) {
900
+ this._logger.warn(`Session ${this._id} timed out, closing`);
901
+ this.close().catch((err)=>{
902
+ this._logger.error(`Error closing timed out session ${this._id}:`, err);
903
+ });
904
+ }
905
+ }, this._timeout);
906
+ }
907
+ /**
908
+ * Reset the timeout timer after activity.
909
+ */ _resetTimeout() {
910
+ this._startTimeout();
911
+ }
912
+ }
913
+ /**
914
+ * ConnectionPool manages multiple concurrent user sessions.
915
+ *
916
+ * Each session has its own server instance with isolated state,
917
+ * allowing multiple users to interact with the system simultaneously.
918
+ */ class ConnectionPool {
919
+ _sessions = new Map();
920
+ _createSessionLock = null;
921
+ _maxSessions;
922
+ _sessionTimeout;
923
+ _autoCleanup;
924
+ _cleanupInterval;
925
+ _cleanupTimerId = null;
926
+ _terminated = false;
927
+ _logger;
928
+ _serverFactory;
929
+ constructor(options = {}){
930
+ this._maxSessions = options.maxSessions ?? 100;
931
+ this._sessionTimeout = options.sessionTimeout ?? 300000; // 5 minutes
932
+ this._autoCleanup = options.autoCleanup ?? true;
933
+ this._cleanupInterval = options.cleanupInterval ?? 60000; // 1 minute
934
+ this._serverFactory = options.serverFactory ?? null;
935
+ this._logger = options.logger ?? this._createNoopLogger();
936
+ if (this._autoCleanup) {
937
+ this._startCleanup();
938
+ }
939
+ }
940
+ /**
941
+ * Create a no-op logger when none is provided.
942
+ */ _createNoopLogger() {
943
+ return {
944
+ info: ()=>{},
945
+ warn: ()=>{},
946
+ error: ()=>{},
947
+ debug: ()=>{},
948
+ setLevel: ()=>{},
949
+ getLevel: ()=>'info'
950
+ };
951
+ }
952
+ /**
953
+ * Create a new session.
954
+ *
955
+ * @returns The session ID
956
+ * @throws Error if max sessions reached
957
+ */ async createSession() {
958
+ while(this._createSessionLock){
959
+ await this._createSessionLock;
960
+ }
961
+ if (this._terminated) {
962
+ throw new _errors_js__rspack_import_0/* .PoolTerminatedError */.m_();
963
+ }
964
+ if (this._sessions.size >= this._maxSessions) {
965
+ throw new _errors_js__rspack_import_0/* .MaxSessionsReachedError */.yM(this._maxSessions);
966
+ }
967
+ if (!this._serverFactory) {
968
+ throw new Error('ConnectionPool requires a serverFactory option to create sessions');
969
+ }
970
+ let resolveLock;
971
+ this._createSessionLock = new Promise((resolve)=>{
972
+ resolveLock = resolve;
973
+ });
974
+ try {
975
+ // Generate unique session ID
976
+ const sessionId = `session_${Date.now()}_${Math.random().toString(36).substring(2, 11)}`;
977
+ // Create a new server instance for this session
978
+ const server = await this._serverFactory();
979
+ // Create session
980
+ const session = new Session(sessionId, server, this._sessionTimeout, this._logger);
981
+ this._sessions.set(sessionId, session);
982
+ this._logger.info(`Created session ${sessionId} (${this._sessions.size}/${this._maxSessions} active sessions)`);
983
+ return sessionId;
984
+ } finally{
985
+ resolveLock();
986
+ this._createSessionLock = null;
987
+ }
988
+ }
989
+ /**
990
+ * Process a thought in the specified session.
991
+ *
992
+ * @param sessionId - The session ID
993
+ * @param input - The thought data to process
994
+ * @returns Promise with the processing result
995
+ * @throws Error if session not found
996
+ */ async process(sessionId, input) {
997
+ const session = this._sessions.get(sessionId);
998
+ if (!session) {
999
+ throw new _errors_js__rspack_import_0/* .SessionNotFoundError */.Ag(sessionId);
1000
+ }
1001
+ return session.process(input);
1002
+ }
1003
+ /**
1004
+ * Close a session and release resources.
1005
+ *
1006
+ * @param sessionId - The session ID to close
1007
+ * @throws Error if session not found
1008
+ */ async closeSession(sessionId) {
1009
+ const session = this._sessions.get(sessionId);
1010
+ if (!session) {
1011
+ throw new _errors_js__rspack_import_0/* .SessionNotFoundError */.Ag(sessionId);
1012
+ }
1013
+ await session.close();
1014
+ this._sessions.delete(sessionId);
1015
+ this._logger.info(`Closed session ${sessionId} (${this._sessions.size}/${this._maxSessions} active sessions)`);
1016
+ }
1017
+ /**
1018
+ * Get information about a session.
1019
+ *
1020
+ * @param sessionId - The session ID
1021
+ * @returns Session info or undefined if not found
1022
+ */ getSessionInfo(sessionId) {
1023
+ return this._sessions.get(sessionId)?.getInfo();
1024
+ }
1025
+ /**
1026
+ * Get all active sessions.
1027
+ *
1028
+ * @returns Array of session information
1029
+ */ getActiveSessions() {
1030
+ return Array.from(this._sessions.values()).filter((s)=>s.isActive).map((s)=>s.getInfo());
1031
+ }
1032
+ /**
1033
+ * Get connection pool statistics.
1034
+ */ getStats() {
1035
+ const activeSessions = this.getActiveSessions();
1036
+ return {
1037
+ totalSessions: this._sessions.size,
1038
+ activeSessions: activeSessions.length,
1039
+ maxSessions: this._maxSessions,
1040
+ cleanupEnabled: this._autoCleanup,
1041
+ sessionTimeout: this._sessionTimeout
1042
+ };
1043
+ }
1044
+ /**
1045
+ * Start the automatic cleanup timer.
1046
+ */ _startCleanup() {
1047
+ if (this._cleanupTimerId !== null) {
1048
+ clearInterval(this._cleanupTimerId);
1049
+ }
1050
+ this._cleanupTimerId = setInterval(()=>{
1051
+ this._cleanupTimedOutSessions();
1052
+ }, this._cleanupInterval);
1053
+ }
1054
+ /**
1055
+ * Remove timed-out sessions.
1056
+ */ _cleanupTimedOutSessions() {
1057
+ let cleaned = 0;
1058
+ for (const [sessionId, session] of this._sessions.entries()){
1059
+ if (session.isTimedOut()) {
1060
+ session.close().catch((err)=>{
1061
+ this._logger.error(`Error closing timed out session ${sessionId}:`, err);
1062
+ });
1063
+ this._sessions.delete(sessionId);
1064
+ cleaned++;
1065
+ }
1066
+ }
1067
+ if (cleaned > 0) {
1068
+ this._logger.info(`Cleaned ${cleaned} timed-out sessions (${this._sessions.size}/${this._maxSessions} active sessions)`);
1069
+ }
1070
+ }
1071
+ /**
1072
+ * Close all sessions and stop the cleanup timer.
1073
+ */ async terminate() {
1074
+ if (this._terminated) {
1075
+ return;
1076
+ }
1077
+ this._terminated = true;
1078
+ // Stop cleanup timer
1079
+ if (this._cleanupTimerId !== null) {
1080
+ clearInterval(this._cleanupTimerId);
1081
+ this._cleanupTimerId = null;
1082
+ }
1083
+ // Close all sessions
1084
+ const closePromises = Array.from(this._sessions.values()).map((session)=>session.close().catch((err)=>{
1085
+ this._logger.error(`Error closing session ${session.getInfo().id}:`, err);
1086
+ }));
1087
+ await Promise.all(closePromises);
1088
+ this._sessions.clear();
1089
+ this._logger.info('ConnectionPool terminated');
1090
+ }
1091
+ /**
1092
+ * Dispose of the connection pool, releasing all resources.
1093
+ * Implements the IDisposable interface.
1094
+ * Delegates to terminate() for backward compatibility.
1095
+ */ async dispose() {
1096
+ await this.terminate();
1097
+ }
1098
+ /**
1099
+ * Check if the connection pool is active.
1100
+ */ isRunning() {
1101
+ return !this._terminated;
1102
+ }
1103
+ }
1104
+ /**
1105
+ * Create a connection pool with the given options.
1106
+ *
1107
+ * @param options - Connection pool configuration
1108
+ * @returns A configured connection pool
1109
+ *
1110
+ * @example
1111
+ * ```typescript
1112
+ * const pool = createConnectionPool({
1113
+ * maxSessions: 50,
1114
+ * sessionTimeout: 300000
1115
+ * });
1116
+ * ```
1117
+ */ function createConnectionPool(options) {
1118
+ return new ConnectionPool(options);
1119
+ }
1120
+
1121
+
1122
+ },
1123
+ 613(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
1124
+ __webpack_require__.d(__webpack_exports__, {
1125
+ Uv: () => (JsonRpcRequestSchema),
1126
+ ZK: () => (SequentialThinkingSchema),
1127
+ iV: () => (SEQUENTIAL_THINKING_TOOL)
1128
+ });
1129
+ /* import */ var valibot__rspack_import_0 = __webpack_require__(821);
1130
+ /**
1131
+ * Valibot validation schemas for the sequential thinking MCP tool.
1132
+ *
1133
+ * This module defines the validation schemas used for the sequential thinking tool,
1134
+ * including schemas for tool recommendations, skill recommendations, step recommendations,
1135
+ * and the main sequential thinking input. All schemas use Valibot for runtime validation
1136
+ * and provide detailed descriptions for MCP protocol compatibility.
1137
+ *
1138
+ * @remarks
1139
+ * **Schema Overview:**
1140
+ * - `ToolRecommendationSchema` - Validates tool recommendation objects with confidence scores
1141
+ * - `SkillRecommendationSchema` - Validates skill recommendation objects
1142
+ * - `StepRecommendationSchema` - Validates step coordination structures
1143
+ * - `SequentialThinkingSchema` - Main schema for thought input validation
1144
+ * - Reasoning enhancement fields: thought_type, quality_score, confidence, hypothesis_id, etc.
1145
+ *
1146
+ * @example
1147
+ * ```typescript
1148
+ * import { SequentialThinkingSchema } from './schema.js';
1149
+ * import { safeParse } from 'valibot';
1150
+ *
1151
+ * const result = safeParse(SequentialThinkingSchema, inputData);
1152
+ * if (result.success) {
1153
+ * const thought = result.output;
1154
+ * // Process the valid thought
1155
+ * } else {
1156
+ * console.error('Validation failed:', result.issues);
1157
+ * }
1158
+ * ```
1159
+ * @module schema
1160
+ */
1161
+ /**
1162
+ * Detailed description for the sequential thinking tool.
1163
+ *
1164
+ * This description is shown to LLMs when they consider using this tool.
1165
+ * It explains when to use the tool, its features, parameters, and best practices.
1166
+ */ const TOOL_DESCRIPTION = `A detailed tool for dynamic and reflective problem-solving through thoughts.
3
1167
  This tool helps analyze problems through a flexible thinking process that can adapt and evolve.
4
1168
  Each thought can build on, question, or revise previous insights as understanding deepens.
5
1169
 
@@ -102,13 +1266,2443 @@ You should:
102
1266
  20. Self-assess quality and confidence to track reasoning reliability
103
1267
  21. Use merge_from_thoughts to combine insights from multiple reasoning branches
104
1268
  22. Use session_id to isolate independent reasoning chains from each other
105
- 23. Use reset_state: true when starting a completely new analysis to avoid statistical contamination from previous chains`,o=i.object({tool_name:i.pipe(i.string(),i.description("Name of the tool being recommended")),confidence:i.pipe(i.number(),i.minValue(0),i.maxValue(1),i.description("0-1 indicating confidence in recommendation")),rationale:i.pipe(i.string(),i.description("Why this tool is recommended")),priority:i.optional(i.pipe(i.number(),i.description("Order in the recommendation sequence (default: 999)"))),suggested_inputs:i.optional(i.pipe(i.record(i.string(),i.unknown()),i.description("Optional suggested parameters"))),alternatives:i.optional(i.pipe(i.array(i.string()),i.description("Alternative tools that could be used")))}),r=i.object({skill_name:i.pipe(i.string(),i.description("Name of the skill being recommended")),confidence:i.optional(i.pipe(i.number(),i.minValue(0),i.maxValue(1),i.description("0-1 indicating confidence in recommendation (default: 0.5)"))),rationale:i.optional(i.pipe(i.string(),i.description("Why this skill is recommended (default: empty string)"))),priority:i.optional(i.pipe(i.number(),i.description("Order in the recommendation sequence (default: 999)"))),alternatives:i.optional(i.pipe(i.array(i.string()),i.description("Alternative skills that could be used"))),allowed_tools:i.optional(i.pipe(i.array(i.string()),i.description("Tools this skill is allowed to use (from skill frontmatter)"))),user_invocable:i.optional(i.pipe(i.boolean(),i.description("Whether this skill can be user-invoked")))}),a=i.object({step_description:i.pipe(i.string(),i.description("What needs to be done")),recommended_tools:i.pipe(i.array(o),i.description("Tools recommended for this step")),recommended_skills:i.optional(i.pipe(i.array(r),i.description("Skills recommended for this step"))),expected_outcome:i.pipe(i.string(),i.description("What to expect from this step")),next_step_conditions:i.optional(i.pipe(i.array(i.string()),i.description("Conditions to consider for the next step")))}),l=i.object({tool_name:i.pipe(i.string(),i.description("Name of the tool being recommended")),rationale:i.optional(i.pipe(i.string(),i.description("Why this tool is recommended (default: empty string)"))),confidence:i.optional(i.pipe(i.number(),i.minValue(0),i.maxValue(1),i.description("0-1 indicating confidence in recommendation (default: 0.5)"))),priority:i.optional(i.pipe(i.number(),i.description("Order in the recommendation sequence (default: 999)"))),suggested_inputs:i.optional(i.pipe(i.record(i.string(),i.unknown()),i.description("Optional suggested parameters"))),alternatives:i.optional(i.pipe(i.array(i.string()),i.description("Alternative tools that could be used")))}),c=i.object({step_description:i.pipe(i.string(),i.description("What needs to be done")),recommended_tools:i.pipe(i.array(l),i.description("Tools recommended for this step")),recommended_skills:i.optional(i.pipe(i.array(r),i.description("Skills recommended for this step"))),expected_outcome:i.optional(i.pipe(i.string(),i.description("What to expect from this step (default: empty string)"))),next_step_conditions:i.optional(i.pipe(i.array(i.string()),i.description("Conditions to consider for the next step")))}),h=i.object({available_mcp_tools:i.optional(i.pipe(i.array(i.string()),i.description('Array of MCP tool names available for use (e.g., ["mcp-omnisearch", "mcp-turso-cloud"])'))),available_skills:i.optional(i.pipe(i.array(i.string()),i.description('Array of skill names available for use (e.g., ["commit", "review-pr", "pdf"])'))),thought:i.pipe(i.string(),i.description("Your current thinking step")),id:i.optional(i.pipe(i.string(),i.minLength(1),i.maxLength(30),i.description("Unique identifier for this thought. Auto-generated if not provided."))),next_thought_needed:i.optional(i.pipe(i.boolean(),i.description("Whether another thought step is needed (defaults to true if not provided)"))),thought_number:i.pipe(i.number(),i.minValue(1),i.description("Current thought number")),total_thoughts:i.pipe(i.number(),i.minValue(1),i.description("Estimated total thoughts needed")),is_revision:i.optional(i.pipe(i.boolean(),i.description("Whether this revises previous thinking"))),revises_thought:i.optional(i.pipe(i.number(),i.minValue(1),i.description("Which thought is being reconsidered"))),branch_from_thought:i.optional(i.pipe(i.number(),i.minValue(1),i.description("Branching point thought number"))),branch_id:i.optional(i.pipe(i.string(),i.regex(/^[a-zA-Z0-9_-]+$/,"Branch ID must contain only letters, numbers, hyphens, and underscores"),i.minLength(1),i.maxLength(50),i.description("Branch identifier (alphanumeric, hyphens, underscores only, max 50 chars)"))),needs_more_thoughts:i.optional(i.pipe(i.boolean(),i.description("If more thoughts are needed"))),current_step:i.optional(i.pipe(a,i.description("Current step recommendation"))),previous_steps:i.optional(i.pipe(i.array(c),i.description("Steps already recommended (lenient schema - allows partial data with defaults)"))),remaining_steps:i.optional(i.pipe(i.array(i.string()),i.description("High-level descriptions of upcoming steps"))),thought_type:i.optional(i.pipe(i.picklist(["regular","hypothesis","verification","critique","synthesis","meta","tool_call","tool_observation","assumption","decomposition","backtrack"]),i.description("Classified purpose: regular (default), hypothesis, verification, critique, synthesis, meta, tool_call (requires toolInterleave), tool_observation (requires toolInterleave), assumption (requires newThoughtTypes), decomposition (requires newThoughtTypes), backtrack (requires newThoughtTypes)"))),quality_score:i.optional(i.pipe(i.number(),i.minValue(0),i.maxValue(1),i.description("Self-assessed quality score (0-1)"))),confidence:i.optional(i.pipe(i.number(),i.minValue(0),i.maxValue(1),i.description("Explicit confidence in correctness (0-1)"))),hypothesis_id:i.optional(i.pipe(i.string(),i.regex(/^[a-zA-Z0-9_-]+$/,"Hypothesis ID must contain only letters, numbers, hyphens, and underscores"),i.minLength(1),i.maxLength(50),i.description("Identifier linking hypothesis to verification thoughts"))),verification_target:i.optional(i.pipe(i.number(),i.minValue(1),i.description("Thought number being verified or critiqued"))),synthesis_sources:i.optional(i.pipe(i.array(i.pipe(i.number(),i.minValue(1))),i.description("Thought numbers being synthesized"))),merge_from_thoughts:i.optional(i.pipe(i.array(i.pipe(i.number(),i.minValue(1))),i.description("Thought numbers from other branches being merged (DAG)"))),merge_branch_ids:i.optional(i.pipe(i.array(i.pipe(i.string(),i.regex(/^[a-zA-Z0-9_-]+$/),i.maxLength(50))),i.description("Branch IDs being merged into current context"))),meta_observation:i.optional(i.pipe(i.string(),i.description("Metacognitive observation about reasoning process"))),reasoning_depth:i.optional(i.pipe(i.picklist(["shallow","moderate","deep"]),i.description("Effort signal: how deep reasoning should go"))),session_id:i.optional(i.pipe(i.string(),i.regex(/^[a-zA-Z0-9_-]+$/,"Session ID must contain only letters, numbers, hyphens, and underscores"),i.minLength(1),i.maxLength(100),i.description("Optional session identifier for state isolation. When provided, thought history, branches, and statistics are scoped to this session. Omitting preserves global behavior."))),reset_state:i.optional(i.pipe(i.boolean(),i.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."))),tool_name:i.optional(i.pipe(i.string(),i.minLength(1),i.description("Name of the tool being invoked (for tool_call thoughts)"))),tool_arguments:i.optional(i.pipe(i.record(i.string(),i.unknown()),i.description("Arguments passed to the tool (for tool_call thoughts)"))),tool_result:i.optional(i.pipe(i.unknown(),i.description("Result returned by the tool (for tool_observation thoughts)"))),continuation_token:i.optional(i.pipe(i.string(),i.minLength(1),i.description("Token for resuming long-running tool invocations"))),decomposition_children:i.optional(i.pipe(i.array(i.string()),i.description("Child thought IDs produced by decomposition"))),backtrack_target:i.optional(i.pipe(i.number(),i.integer(),i.minValue(1),i.description("Thought number to backtrack to. When the parent thought has thought_type=backtrack, this thought is logically retracted: it remains in history but is excluded from quality signals and reasoning stats."))),register_branch_id:i.optional(i.pipe(i.string(),i.regex(/^[a-zA-Z0-9_-]+$/,"register_branch_id must contain only letters, numbers, hyphens, and underscores"),i.minLength(1),i.maxLength(50),i.description("Pre-declares a branch ID for this session before any thoughts reference it. Useful so that subsequent thoughts using merge_branch_ids can target a branch that has not yet received any thoughts.")))}),p={name:"sequentialthinking_tools",description:n,inputSchema:{}},d=i.object({jsonrpc:i.pipe(i.string(),i.literal("2.0"),i.description('JSON-RPC protocol version (must be "2.0")')),method:i.pipe(i.string(),i.minLength(1),i.description("Method name to invoke")),params:i.optional(i.pipe(i.union([i.object({}),i.array(i.unknown())]),i.description("Method parameters (object or array)"))),id:i.optional(i.pipe(i.union([i.string(),i.number(),i.null()]),i.description("Request ID (omit for notifications)")))}),u=i.union([i.literal("sequence"),i.literal("branch"),i.literal("merge"),i.literal("verifies"),i.literal("critiques"),i.literal("derives_from"),i.literal("tool_invocation"),i.literal("revises")]);i.object({id:i.pipe(i.string(),i.minLength(1),i.maxLength(30)),from:i.pipe(i.string(),i.minLength(1),i.maxLength(30)),to:i.pipe(i.string(),i.minLength(1),i.maxLength(30)),kind:u,sessionId:i.pipe(i.string(),i.minLength(1)),createdAt:i.number(),metadata:i.optional(i.record(i.string(),i.unknown()))})},681(e,t,s){s.d(t,{j:()=>r}),s(561);let i=/^[a-zA-Z0-9_-]+$/;class n{_level="info";info(e,t){}warn(e,t){}error(e,t){}debug(e,t){}setLevel(e){this._level=e}getLevel(){return this._level}}let o=new Set(["session","sessionId","client","clientId"]);class r{_port;_host;_corsOrigin;_enableCors;_rateLimitEnabled;_maxRequestsPerMinute;_allowedHosts;_rateLimitMap=new Map;_rateLimitCleanupIntervalId=null;_wasHostExplicitlySet;_isShuttingDown=!1;_logger;_healthChecker;constructor(e={}){this._port=e.port??9108,this._host=e.host??"127.0.0.1",this._wasHostExplicitlySet=void 0!==e.host,this._corsOrigin=e.corsOrigin??"*",this._enableCors=e.enableCors??!0,this._rateLimitEnabled=e.enableRateLimit??!0,this._maxRequestsPerMinute=e.maxRequestsPerMinute??100,this._allowedHosts=this._buildAllowedHosts(e.allowedHosts),this._isShuttingDown=!1,this._logger=e.logger??new n,this._healthChecker=e.healthChecker??null,this._rateLimitEnabled&&this._startRateLimitCleanup()}get serverUrl(){let e=this._wasHostExplicitlySet||"127.0.0.1"!==this._host?this._host:"localhost";return`http://${e}:${this._port}`}validateSessionId(e){return!(e.length>100)&&i.test(e)}sanitizeQueryParams(e){let t={};for(let[s,i]of e.searchParams.entries())o.has(s)&&(t[s]=i);return t}checkRateLimit(e){if(!this._rateLimitEnabled)return!1;let t=Date.now();this._cleanupExpiredRateLimitEntries(t);let s=this._rateLimitMap.get(e);return!s||t>s.resetTime?(this._rateLimitMap.set(e,{count:1,resetTime:t+6e4}),!1):s.count>=this._maxRequestsPerMinute||(s.count++,!1)}_cleanupExpiredRateLimitEntries(e=Date.now()){for(let[t,s]of this._rateLimitMap.entries())s.resetTime<=e&&this._rateLimitMap.delete(t)}_startRateLimitCleanup(){null!==this._rateLimitCleanupIntervalId&&clearInterval(this._rateLimitCleanupIntervalId),this._rateLimitCleanupIntervalId=setInterval(()=>{this._cleanupExpiredRateLimitEntries()},6e4)}_stopRateLimitCleanup(){null!==this._rateLimitCleanupIntervalId&&(clearInterval(this._rateLimitCleanupIntervalId),this._rateLimitCleanupIntervalId=null)}getClientIp(e){let t=e.headers["x-forwarded-for"];return t&&"string"==typeof t?t.split(",")[0].trim():e.socket.remoteAddress||"unknown"}validateCorsOrigin(e){if("*"===this._corsOrigin)return!0;let t=e.headers.origin;if(!t||this._corsOrigin===t)return!0;if(this._corsOrigin.includes("*")){let e=this._corsOrigin.replace(/[.+?^${}()|[\]\\]/g,"\\$&").replace(/\*/g,"[a-zA-Z0-9.-]*");return RegExp(`^${e}$`).test(t)}return!1}setCorsHeaders(e){this._enableCors&&(e.setHeader("Access-Control-Allow-Origin",this._corsOrigin),e.setHeader("Access-Control-Allow-Methods","GET, POST, OPTIONS"),e.setHeader("Access-Control-Allow-Headers","Content-Type"))}validateHostHeader(e){let t=e.headers.host;if(!t)return!0;let s=t.split(":")[0].trim().toLowerCase();return!!s&&(0===this._allowedHosts.size||this._allowedHosts.has(s))}_buildAllowedHosts(e){if(e&&e.length>0)return new Set(e.map(e=>e.toLowerCase().trim()).filter(Boolean));let t=this._host.toLowerCase(),s=["localhost","127.0.0.1","::1"];return new Set(s.includes(t)||"0.0.0.0"===t||"::"===t?s:[t])}log(e,t,s){"info"===e?this._logger.info(t,s):"warn"===e?this._logger.warn(t,s):this._logger.error(t,s)}isShuttingDown(){return this._isShuttingDown}handleHealthEndpoint(e,t){let s={status:"healthy",...t};this._healthChecker&&(s.liveness=this._healthChecker.checkLiveness()),e.writeHead(200,{"Content-Type":"application/json"}),e.end(JSON.stringify(s))}async handleReadinessEndpoint(e){if(this._healthChecker){let t=await this._healthChecker.checkReadiness(),s="ok"===t.status?200:503;e.writeHead(s,{"Content-Type":"application/json"}),e.end(JSON.stringify(t))}else e.writeHead(200,{"Content-Type":"application/json"}),e.end(JSON.stringify({status:"ok",timestamp:new Date().toISOString(),components:{}}))}handleMetricsEndpoint(e,t){if(!t){e.writeHead(404,{"Content-Type":"text/plain"}),e.end("Not Found");return}e.writeHead(200,{"Content-Type":"text/plain; version=0.0.4; charset=utf-8"}),e.end(t())}}},504(e,t,s){s.d(t,{SseTransport:()=>l});var i=s(316),n=s(61),o=s(821),r=s(555),a=s(681);class l extends a.j{_server;_path;_clients=new Set;_clientSessionMap=new Map;_messageQueue=new Map;_metrics;_connectionPool;constructor(e={}){super(e),this._path=e.path??"/sse",this._metrics=e.metrics,this._connectionPool=e.connectionPool,this._updateActiveConnectionsMetric(),this._server=(0,i.createServer)((e,t)=>this._handleRequest(e,t))}async connect(e){return this._mcpServer=e,new Promise(e=>{this._server.listen(this._port,this._host,()=>{this.log("info",`SSE transport listening on http://${this._host}:${this._port}`),e()})})}_mcpServer=null;async _handleRequest(e,t){var s,i,o,r,a;let l=Date.now(),c=e.url||"/",h=e.method||"GET";if(null==(s=this._metrics)||s.counter("http_requests_total",1,{transport:"sse",method:h,path:c},"Total HTTP requests"),t.once("finish",()=>{var e;let t=(Date.now()-l)/1e3;null==(e=this._metrics)||e.histogram("http_request_duration_seconds",t,{transport:"sse",path:c})}),!this.validateHostHeader(e)){null==(i=this._metrics)||i.counter("http_request_errors_total",1,{transport:"sse",error_type:"forbidden"},"Total HTTP request errors"),t.writeHead(403,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Forbidden - invalid host header"}));return}let p=new n.URL(e.url||"",`http://${e.headers.host}`),d=this.getClientIp(e);if(this.checkRateLimit(d)){null==(o=this._metrics)||o.counter("http_request_errors_total",1,{transport:"sse",error_type:"rate_limit"},"Total HTTP request errors"),t.writeHead(429,{"Content-Type":"application/json","Retry-After":"60"}),t.end(JSON.stringify({error:"Too many requests"}));return}if(!this.validateCorsOrigin(e)){null==(r=this._metrics)||r.counter("http_request_errors_total",1,{transport:"sse",error_type:"forbidden"},"Total HTTP request errors"),t.writeHead(403,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Forbidden - invalid origin"}));return}this.setCorsHeaders(t);let u=this.sanitizeQueryParams(p);if(u.session||u.sessionId){let e=u.session??u.sessionId;if(!this.validateSessionId(e)){null==(a=this._metrics)||a.counter("http_request_errors_total",1,{transport:"sse",error_type:"validation"},"Total HTTP request errors"),t.writeHead(400,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Invalid session ID format"}));return}}if(this._enableCors&&"OPTIONS"===e.method){t.writeHead(204),t.end();return}p.pathname===this._path&&"GET"===e.method?await this._handleSseConnection(e,t,u):p.pathname===`${this._path}/message`&&"POST"===e.method?await this._handleMessage(e,t,u):"/health"===p.pathname?this._handleHealthCheck(t):"/ready"===p.pathname?await this._handleReadinessCheck(t):(t.writeHead(404,{"Content-Type":"text/plain"}),t.end("Not Found"))}_handleHealthCheck(e){let t={status:"healthy",clients:this._clients.size};this._connectionPool&&(t.pool=this._connectionPool.getStats()),this._healthChecker&&(t.liveness=this._healthChecker.checkLiveness()),e.writeHead(200,{"Content-Type":"application/json"}),e.end(JSON.stringify(t))}async _handleReadinessCheck(e){if(this._healthChecker){let t=await this._healthChecker.checkReadiness(),s="ok"===t.status?200:503;e.writeHead(s,{"Content-Type":"application/json"}),e.end(JSON.stringify(t))}else e.writeHead(200,{"Content-Type":"application/json"}),e.end(JSON.stringify({status:"ok",timestamp:new Date().toISOString(),components:{}}))}async _handleSseConnection(e,t,s){let i;if(t.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive"}),this._connectionPool){let e=s.session??s.sessionId;if(e&&this._connectionPool.getSessionInfo(e))i=e;else try{i=await this._connectionPool.createSession()}catch(e){t.write(`event: error
106
- `),t.write(`data: ${JSON.stringify({error:e instanceof Error?e.message:"Failed to create session"})}
1269
+ 23. Use reset_state: true when starting a completely new analysis to avoid statistical contamination from previous chains`;
1270
+ /**
1271
+ * Valibot schema for validating tool recommendation objects.
1272
+ *
1273
+ * Validates that a tool recommendation has:
1274
+ * - A tool name (string)
1275
+ * - A confidence score between 0 and 1
1276
+ * - A rationale explaining the recommendation
1277
+ * - A priority number for ordering
1278
+ * - Optional suggested input parameters
1279
+ * - Optional alternative tools
1280
+ *
1281
+ * @example
1282
+ * ```typescript
1283
+ * import { safeParse } from 'valibot';
1284
+ * import { ToolRecommendationSchema } from './schema.js';
1285
+ *
1286
+ * const result = safeParse(ToolRecommendationSchema, {
1287
+ * tool_name: 'mcp__tavily-mcp__tavily-search',
1288
+ * confidence: 0.9,
1289
+ * rationale: 'Best for web search',
1290
+ * priority: 1
1291
+ * });
1292
+ * ```
1293
+ */ const ToolRecommendationSchema = valibot__rspack_import_0.object({
1294
+ tool_name: valibot__rspack_import_0.pipe(valibot__rspack_import_0.string(), valibot__rspack_import_0.description('Name of the tool being recommended')),
1295
+ confidence: valibot__rspack_import_0.pipe(valibot__rspack_import_0.number(), valibot__rspack_import_0.minValue(0), valibot__rspack_import_0.maxValue(1), valibot__rspack_import_0.description('0-1 indicating confidence in recommendation')),
1296
+ rationale: valibot__rspack_import_0.pipe(valibot__rspack_import_0.string(), valibot__rspack_import_0.maxLength(2000), valibot__rspack_import_0.description('Why this tool is recommended')),
1297
+ priority: valibot__rspack_import_0.optional(valibot__rspack_import_0.pipe(valibot__rspack_import_0.number(), valibot__rspack_import_0.description('Order in the recommendation sequence (default: 999)'))),
1298
+ suggested_inputs: valibot__rspack_import_0.optional(valibot__rspack_import_0.pipe(valibot__rspack_import_0.record(valibot__rspack_import_0.string(), valibot__rspack_import_0.union([
1299
+ valibot__rspack_import_0.string(),
1300
+ valibot__rspack_import_0.number(),
1301
+ valibot__rspack_import_0.boolean(),
1302
+ valibot__rspack_import_0["null"]()
1303
+ ])), valibot__rspack_import_0.description('Optional suggested parameters (flat key-value pairs only)'))),
1304
+ alternatives: valibot__rspack_import_0.optional(valibot__rspack_import_0.pipe(valibot__rspack_import_0.array(valibot__rspack_import_0.string()), valibot__rspack_import_0.description('Alternative tools that could be used')))
1305
+ });
1306
+ /**
1307
+ * Valibot schema for validating skill recommendation objects.
1308
+ *
1309
+ * Validates that a skill recommendation has:
1310
+ * - A skill name (string)
1311
+ * - A confidence score between 0 and 1
1312
+ * - A rationale explaining the recommendation
1313
+ * - A priority number for ordering
1314
+ * - Optional alternative skills
1315
+ * - Optional allowed tools list
1316
+ * - Optional user invocable flag
1317
+ *
1318
+ * @example
1319
+ * ```typescript
1320
+ * import { safeParse } from 'valibot';
1321
+ * import { SkillRecommendationSchema } from './schema.js';
1322
+ *
1323
+ * const result = safeParse(SkillRecommendationSchema, {
1324
+ * skill_name: 'commit',
1325
+ * confidence: 0.95,
1326
+ * rationale: 'Handles git commit workflow',
1327
+ * priority: 1,
1328
+ * user_invocable: true
1329
+ * });
1330
+ * ```
1331
+ */ const SkillRecommendationSchema = valibot__rspack_import_0.object({
1332
+ skill_name: valibot__rspack_import_0.pipe(valibot__rspack_import_0.string(), valibot__rspack_import_0.description('Name of the skill being recommended')),
1333
+ confidence: valibot__rspack_import_0.optional(valibot__rspack_import_0.pipe(valibot__rspack_import_0.number(), valibot__rspack_import_0.minValue(0), valibot__rspack_import_0.maxValue(1), valibot__rspack_import_0.description('0-1 indicating confidence in recommendation (default: 0.5)'))),
1334
+ rationale: valibot__rspack_import_0.optional(valibot__rspack_import_0.pipe(valibot__rspack_import_0.string(), valibot__rspack_import_0.maxLength(2000), valibot__rspack_import_0.description('Why this skill is recommended (default: empty string)'))),
1335
+ priority: valibot__rspack_import_0.optional(valibot__rspack_import_0.pipe(valibot__rspack_import_0.number(), valibot__rspack_import_0.description('Order in the recommendation sequence (default: 999)'))),
1336
+ alternatives: valibot__rspack_import_0.optional(valibot__rspack_import_0.pipe(valibot__rspack_import_0.array(valibot__rspack_import_0.string()), valibot__rspack_import_0.description('Alternative skills that could be used'))),
1337
+ allowed_tools: valibot__rspack_import_0.optional(valibot__rspack_import_0.pipe(valibot__rspack_import_0.array(valibot__rspack_import_0.string()), valibot__rspack_import_0.description('Tools this skill is allowed to use (from skill frontmatter)'))),
1338
+ user_invocable: valibot__rspack_import_0.optional(valibot__rspack_import_0.pipe(valibot__rspack_import_0.boolean(), valibot__rspack_import_0.description('Whether this skill can be user-invoked')))
1339
+ });
1340
+ /**
1341
+ * Valibot schema for validating step recommendation objects.
1342
+ *
1343
+ * Validates that a step recommendation has:
1344
+ * - A step description
1345
+ * - An array of recommended tools
1346
+ * - An optional array of recommended skills
1347
+ * - An expected outcome
1348
+ * - Optional conditions for the next step
1349
+ *
1350
+ * @example
1351
+ * ```typescript
1352
+ * import { safeParse } from 'valibot';
1353
+ * import { StepRecommendationSchema } from './schema.js';
1354
+ *
1355
+ * const result = safeParse(StepRecommendationSchema, {
1356
+ * step_description: 'Search for TypeScript files',
1357
+ * recommended_tools: [{ ... }],
1358
+ * expected_outcome: 'List of all TypeScript files'
1359
+ * });
1360
+ * ```
1361
+ */ const StepRecommendationSchema = valibot__rspack_import_0.object({
1362
+ step_description: valibot__rspack_import_0.pipe(valibot__rspack_import_0.string(), valibot__rspack_import_0.description('What needs to be done')),
1363
+ recommended_tools: valibot__rspack_import_0.pipe(valibot__rspack_import_0.array(ToolRecommendationSchema), valibot__rspack_import_0.description('Tools recommended for this step')),
1364
+ recommended_skills: valibot__rspack_import_0.optional(valibot__rspack_import_0.pipe(valibot__rspack_import_0.array(SkillRecommendationSchema), valibot__rspack_import_0.description('Skills recommended for this step'))),
1365
+ expected_outcome: valibot__rspack_import_0.pipe(valibot__rspack_import_0.string(), valibot__rspack_import_0.description('What to expect from this step')),
1366
+ next_step_conditions: valibot__rspack_import_0.optional(valibot__rspack_import_0.pipe(valibot__rspack_import_0.array(valibot__rspack_import_0.string()), valibot__rspack_import_0.description('Conditions to consider for the next step')))
1367
+ });
1368
+ /**
1369
+ * Valibot schema for validating partial tool recommendation objects.
1370
+ *
1371
+ * This is a lenient version of ToolRecommendationSchema used for previous_steps,
1372
+ * where LLMs naturally provide partial/skeletal data. Only tool_name and rationale
1373
+ * are required, while confidence and priority are optional with default values.
1374
+ *
1375
+ * Validates that a partial tool recommendation has:
1376
+ * - A tool name (required)
1377
+ * - A rationale explaining the recommendation (required)
1378
+ * - An optional confidence score (defaults to 0.5)
1379
+ * - An optional priority number (defaults to 999)
1380
+ * - Optional suggested input parameters
1381
+ * - Optional alternative tools
1382
+ *
1383
+ * @remarks
1384
+ * **Design Rationale:**
1385
+ * LLMs tend to provide complete data for current_step but only partial data
1386
+ * for previous_steps (historical context). This schema accommodates that natural
1387
+ * LLM behavior while maintaining data integrity through sensible defaults.
1388
+ *
1389
+ * @example
1390
+ * ```typescript
1391
+ * import { safeParse } from 'valibot';
1392
+ * import { PartialToolRecommendationSchema } from './schema.js';
1393
+ *
1394
+ * // Minimal valid input (LLM often generates this for previous_steps)
1395
+ * const result = safeParse(PartialToolRecommendationSchema, {
1396
+ * tool_name: 'Read',
1397
+ * rationale: 'Read the file'
1398
+ * });
1399
+ * // confidence and priority will be filled in by the normalizer
1400
+ * ```
1401
+ */ const PartialToolRecommendationSchema = valibot__rspack_import_0.object({
1402
+ tool_name: valibot__rspack_import_0.pipe(valibot__rspack_import_0.string(), valibot__rspack_import_0.description('Name of the tool being recommended')),
1403
+ rationale: valibot__rspack_import_0.optional(valibot__rspack_import_0.pipe(valibot__rspack_import_0.string(), valibot__rspack_import_0.maxLength(2000), valibot__rspack_import_0.description('Why this tool is recommended (default: empty string)'))),
1404
+ confidence: valibot__rspack_import_0.optional(valibot__rspack_import_0.pipe(valibot__rspack_import_0.number(), valibot__rspack_import_0.minValue(0), valibot__rspack_import_0.maxValue(1), valibot__rspack_import_0.description('0-1 indicating confidence in recommendation (default: 0.5)'))),
1405
+ priority: valibot__rspack_import_0.optional(valibot__rspack_import_0.pipe(valibot__rspack_import_0.number(), valibot__rspack_import_0.description('Order in the recommendation sequence (default: 999)'))),
1406
+ suggested_inputs: valibot__rspack_import_0.optional(valibot__rspack_import_0.pipe(valibot__rspack_import_0.record(valibot__rspack_import_0.string(), valibot__rspack_import_0.union([
1407
+ valibot__rspack_import_0.string(),
1408
+ valibot__rspack_import_0.number(),
1409
+ valibot__rspack_import_0.boolean(),
1410
+ valibot__rspack_import_0["null"]()
1411
+ ])), valibot__rspack_import_0.description('Optional suggested parameters (flat key-value pairs only)'))),
1412
+ alternatives: valibot__rspack_import_0.optional(valibot__rspack_import_0.pipe(valibot__rspack_import_0.array(valibot__rspack_import_0.string()), valibot__rspack_import_0.description('Alternative tools that could be used')))
1413
+ });
1414
+ /**
1415
+ * Valibot schema for validating partial step recommendation objects.
1416
+ *
1417
+ * This is a lenient version of StepRecommendationSchema used for previous_steps,
1418
+ * where LLMs naturally provide partial/skeletal data. Only step_description is
1419
+ * strictly required, while expected_outcome and tool recommendation fields are
1420
+ * optional with default values.
1421
+ *
1422
+ * Validates that a partial step recommendation has:
1423
+ * - A step description (required)
1424
+ * - An array of recommended tools (with optional confidence/priority)
1425
+ * - An optional array of recommended skills
1426
+ * - An optional expected outcome (defaults to empty string)
1427
+ * - Optional conditions for the next step
1428
+ *
1429
+ * @remarks
1430
+ * **Design Rationale:**
1431
+ * LLMs provide complete, detailed data for current_step but only brief summaries
1432
+ * for previous_steps. This schema allows the natural LLM behavior while the
1433
+ * InputNormalizer fills in sensible defaults for missing fields.
1434
+ *
1435
+ * @example
1436
+ * ```typescript
1437
+ * import { safeParse } from 'valibot';
1438
+ * import { PartialStepRecommendationSchema } from './schema.js';
1439
+ *
1440
+ * // Minimal valid input (LLM often generates this for previous_steps)
1441
+ * const result = safeParse(PartialStepRecommendationSchema, {
1442
+ * step_description: 'Read the file',
1443
+ * recommended_tools: [{
1444
+ * tool_name: 'Read',
1445
+ * rationale: 'Read the file'
1446
+ * }]
1447
+ * });
1448
+ * // confidence, priority, and expected_outcome will be filled in by normalizer
1449
+ * ```
1450
+ */ const PartialStepRecommendationSchema = valibot__rspack_import_0.object({
1451
+ step_description: valibot__rspack_import_0.pipe(valibot__rspack_import_0.string(), valibot__rspack_import_0.description('What needs to be done')),
1452
+ recommended_tools: valibot__rspack_import_0.pipe(valibot__rspack_import_0.array(PartialToolRecommendationSchema), valibot__rspack_import_0.description('Tools recommended for this step')),
1453
+ recommended_skills: valibot__rspack_import_0.optional(valibot__rspack_import_0.pipe(valibot__rspack_import_0.array(SkillRecommendationSchema), valibot__rspack_import_0.description('Skills recommended for this step'))),
1454
+ expected_outcome: valibot__rspack_import_0.optional(valibot__rspack_import_0.pipe(valibot__rspack_import_0.string(), valibot__rspack_import_0.description('What to expect from this step (default: empty string)'))),
1455
+ next_step_conditions: valibot__rspack_import_0.optional(valibot__rspack_import_0.pipe(valibot__rspack_import_0.array(valibot__rspack_import_0.string()), valibot__rspack_import_0.description('Conditions to consider for the next step')))
1456
+ });
1457
+ /**
1458
+ * Main Valibot schema for validating sequential thinking tool input.
1459
+ *
1460
+ * This is the primary schema used for the sequential thinking MCP tool.
1461
+ * It validates all thought data including:
1462
+ * - Optional available tools and skills arrays
1463
+ * - The thought content (required)
1464
+ * - Thought numbering (thought_number, total_thoughts)
1465
+ * - Revision and branching metadata
1466
+ * - Current, previous, and remaining step recommendations
1467
+ *
1468
+ * @remarks
1469
+ * **Validation Rules:**
1470
+ * - `thought_number` must be >= 1
1471
+ * - `total_thoughts` must be >= 1
1472
+ * - `branch_id` must be 1-50 characters, alphanumeric/hyphens/underscores only
1473
+ * - `confidence` values must be between 0 and 1
1474
+ * - `thought_type` must be one of: regular, hypothesis, verification, critique, synthesis, meta
1475
+ * - `quality_score` and `confidence` must be between 0 and 1
1476
+ * - `hypothesis_id` must be 1-50 characters, alphanumeric/hyphens/underscores only
1477
+ *
1478
+ * @example
1479
+ * ```typescript
1480
+ * import { safeParse } from 'valibot';
1481
+ * import { SequentialThinkingSchema } from './schema.js';
1482
+ *
1483
+ * const result = safeParse(SequentialThinkingSchema, {
1484
+ * thought: 'I need to analyze the problem',
1485
+ * thought_number: 1,
1486
+ * total_thoughts: 5,
1487
+ * next_thought_needed: true,
1488
+ * available_mcp_tools: ['Read', 'Write', 'Grep']
1489
+ * });
1490
+ *
1491
+ * if (result.success) {
1492
+ * console.log('Valid thought:', result.output);
1493
+ * } else {
1494
+ * console.error('Validation errors:', result.issues);
1495
+ * }
1496
+ * ```
1497
+ */ const SequentialThinkingSchema = valibot__rspack_import_0.object({
1498
+ available_mcp_tools: valibot__rspack_import_0.optional(valibot__rspack_import_0.pipe(valibot__rspack_import_0.array(valibot__rspack_import_0.string()), valibot__rspack_import_0.description('Array of MCP tool names available for use (e.g., ["mcp-omnisearch", "mcp-turso-cloud"])'))),
1499
+ available_skills: valibot__rspack_import_0.optional(valibot__rspack_import_0.pipe(valibot__rspack_import_0.array(valibot__rspack_import_0.string()), valibot__rspack_import_0.description('Array of skill names available for use (e.g., ["commit", "review-pr", "pdf"])'))),
1500
+ thought: valibot__rspack_import_0.pipe(valibot__rspack_import_0.string(), valibot__rspack_import_0.description('Your current thinking step')),
1501
+ id: 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.maxLength(30), valibot__rspack_import_0.description('Unique identifier for this thought. Auto-generated if not provided.'))),
1502
+ next_thought_needed: valibot__rspack_import_0.optional(valibot__rspack_import_0.pipe(valibot__rspack_import_0.boolean(), valibot__rspack_import_0.description('Whether another thought step is needed (defaults to true if not provided)'))),
1503
+ thought_number: valibot__rspack_import_0.pipe(valibot__rspack_import_0.number(), valibot__rspack_import_0.minValue(1), valibot__rspack_import_0.description('Current thought number')),
1504
+ total_thoughts: valibot__rspack_import_0.pipe(valibot__rspack_import_0.number(), valibot__rspack_import_0.minValue(1), valibot__rspack_import_0.description('Estimated total thoughts needed')),
1505
+ is_revision: valibot__rspack_import_0.optional(valibot__rspack_import_0.pipe(valibot__rspack_import_0.boolean(), valibot__rspack_import_0.description('Whether this revises previous thinking'))),
1506
+ revises_thought: valibot__rspack_import_0.optional(valibot__rspack_import_0.pipe(valibot__rspack_import_0.number(), valibot__rspack_import_0.minValue(1), valibot__rspack_import_0.description('Which thought is being reconsidered'))),
1507
+ branch_from_thought: valibot__rspack_import_0.optional(valibot__rspack_import_0.pipe(valibot__rspack_import_0.number(), valibot__rspack_import_0.minValue(1), valibot__rspack_import_0.description('Branching point thought number'))),
1508
+ branch_id: valibot__rspack_import_0.optional(valibot__rspack_import_0.pipe(valibot__rspack_import_0.string(), valibot__rspack_import_0.regex(/^[a-zA-Z0-9_-]+$/, 'Branch ID must contain only letters, numbers, hyphens, and underscores'), valibot__rspack_import_0.minLength(1), valibot__rspack_import_0.maxLength(50), valibot__rspack_import_0.description('Branch identifier (alphanumeric, hyphens, underscores only, max 50 chars)'))),
1509
+ needs_more_thoughts: valibot__rspack_import_0.optional(valibot__rspack_import_0.pipe(valibot__rspack_import_0.boolean(), valibot__rspack_import_0.description('If more thoughts are needed'))),
1510
+ current_step: valibot__rspack_import_0.optional(valibot__rspack_import_0.pipe(StepRecommendationSchema, valibot__rspack_import_0.description('Current step recommendation'))),
1511
+ previous_steps: valibot__rspack_import_0.optional(valibot__rspack_import_0.pipe(valibot__rspack_import_0.array(PartialStepRecommendationSchema), valibot__rspack_import_0.description('Steps already recommended (lenient schema - allows partial data with defaults)'))),
1512
+ remaining_steps: valibot__rspack_import_0.optional(valibot__rspack_import_0.pipe(valibot__rspack_import_0.array(valibot__rspack_import_0.string()), valibot__rspack_import_0.description('High-level descriptions of upcoming steps'))),
1513
+ thought_type: valibot__rspack_import_0.optional(valibot__rspack_import_0.pipe(valibot__rspack_import_0.picklist([
1514
+ 'regular',
1515
+ 'hypothesis',
1516
+ 'verification',
1517
+ 'critique',
1518
+ 'synthesis',
1519
+ 'meta',
1520
+ 'tool_call',
1521
+ 'tool_observation',
1522
+ 'assumption',
1523
+ 'decomposition',
1524
+ 'backtrack'
1525
+ ]), valibot__rspack_import_0.description('Classified purpose: regular (default), hypothesis, verification, critique, synthesis, meta, tool_call (requires toolInterleave), tool_observation (requires toolInterleave), assumption (requires newThoughtTypes), decomposition (requires newThoughtTypes), backtrack (requires newThoughtTypes)'))),
1526
+ quality_score: valibot__rspack_import_0.optional(valibot__rspack_import_0.pipe(valibot__rspack_import_0.number(), valibot__rspack_import_0.minValue(0), valibot__rspack_import_0.maxValue(1), valibot__rspack_import_0.description('Self-assessed quality score (0-1)'))),
1527
+ confidence: valibot__rspack_import_0.optional(valibot__rspack_import_0.pipe(valibot__rspack_import_0.number(), valibot__rspack_import_0.minValue(0), valibot__rspack_import_0.maxValue(1), valibot__rspack_import_0.description('Explicit confidence in correctness (0-1)'))),
1528
+ hypothesis_id: valibot__rspack_import_0.optional(valibot__rspack_import_0.pipe(valibot__rspack_import_0.string(), valibot__rspack_import_0.regex(/^[a-zA-Z0-9_-]+$/, 'Hypothesis ID must contain only letters, numbers, hyphens, and underscores'), valibot__rspack_import_0.minLength(1), valibot__rspack_import_0.maxLength(50), valibot__rspack_import_0.description('Identifier linking hypothesis to verification thoughts'))),
1529
+ verification_target: valibot__rspack_import_0.optional(valibot__rspack_import_0.pipe(valibot__rspack_import_0.number(), valibot__rspack_import_0.minValue(1), valibot__rspack_import_0.description('Thought number being verified or critiqued'))),
1530
+ synthesis_sources: valibot__rspack_import_0.optional(valibot__rspack_import_0.pipe(valibot__rspack_import_0.array(valibot__rspack_import_0.pipe(valibot__rspack_import_0.number(), valibot__rspack_import_0.minValue(1))), valibot__rspack_import_0.description('Thought numbers being synthesized'))),
1531
+ merge_from_thoughts: valibot__rspack_import_0.optional(valibot__rspack_import_0.pipe(valibot__rspack_import_0.array(valibot__rspack_import_0.pipe(valibot__rspack_import_0.number(), valibot__rspack_import_0.minValue(1))), valibot__rspack_import_0.description('Thought numbers from other branches being merged (DAG)'))),
1532
+ merge_branch_ids: valibot__rspack_import_0.optional(valibot__rspack_import_0.pipe(valibot__rspack_import_0.array(valibot__rspack_import_0.pipe(valibot__rspack_import_0.string(), valibot__rspack_import_0.regex(/^[a-zA-Z0-9_-]+$/), valibot__rspack_import_0.maxLength(50))), valibot__rspack_import_0.description('Branch IDs being merged into current context'))),
1533
+ meta_observation: valibot__rspack_import_0.optional(valibot__rspack_import_0.pipe(valibot__rspack_import_0.string(), valibot__rspack_import_0.description('Metacognitive observation about reasoning process'))),
1534
+ reasoning_depth: valibot__rspack_import_0.optional(valibot__rspack_import_0.pipe(valibot__rspack_import_0.picklist([
1535
+ 'shallow',
1536
+ 'moderate',
1537
+ 'deep'
1538
+ ]), valibot__rspack_import_0.description('Effort signal: how deep reasoning should go'))),
1539
+ session_id: valibot__rspack_import_0.optional(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.description('Optional session identifier for state isolation. When provided, thought history, branches, and statistics are scoped to this session. Omitting preserves global behavior.'))),
1540
+ 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.'))),
1541
+ 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)'))),
1542
+ 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)'))),
1543
+ tool_result: valibot__rspack_import_0.optional(valibot__rspack_import_0.pipe(valibot__rspack_import_0.unknown(), valibot__rspack_import_0.description('Result returned by the tool (for tool_observation thoughts)'))),
1544
+ continuation_token: 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('Token for resuming long-running tool invocations'))),
1545
+ decomposition_children: valibot__rspack_import_0.optional(valibot__rspack_import_0.pipe(valibot__rspack_import_0.array(valibot__rspack_import_0.string()), valibot__rspack_import_0.description('Child thought IDs produced by decomposition'))),
1546
+ backtrack_target: valibot__rspack_import_0.optional(valibot__rspack_import_0.pipe(valibot__rspack_import_0.number(), valibot__rspack_import_0.integer(), valibot__rspack_import_0.minValue(1), valibot__rspack_import_0.description('Thought number to backtrack to. When the parent thought has thought_type=backtrack, this thought is logically retracted: it remains in history but is excluded from quality signals and reasoning stats.'))),
1547
+ register_branch_id: valibot__rspack_import_0.optional(valibot__rspack_import_0.pipe(valibot__rspack_import_0.string(), valibot__rspack_import_0.regex(/^[a-zA-Z0-9_-]+$/, 'register_branch_id must contain only letters, numbers, hyphens, and underscores'), valibot__rspack_import_0.minLength(1), valibot__rspack_import_0.maxLength(50), valibot__rspack_import_0.description('Pre-declares a branch ID for this session before any thoughts reference it. Useful so that subsequent thoughts using merge_branch_ids can target a branch that has not yet received any thoughts.')))
1548
+ });
1549
+ /**
1550
+ * The sequential thinking tool definition for MCP registration.
1551
+ *
1552
+ * This object defines the tool that is registered with the MCP server.
1553
+ * The inputSchema is left empty as the schema is handled by tmcp
1554
+ * when registering the tool using the Valibot adapter.
1555
+ *
1556
+ * @example
1557
+ * ```typescript
1558
+ * import { SEQUENTIAL_THINKING_TOOL } from './schema.js';
1559
+ * import { McpServer } from 'tmcp';
1560
+ *
1561
+ * const server = new McpServer({ name: 'my-server', version: '1.0.0' });
1562
+ * server.tool({
1563
+ * name: SEQUENTIAL_THINKING_TOOL.name,
1564
+ * description: SEQUENTIAL_THINKING_TOOL.description,
1565
+ * schema: SequentialThinkingSchema
1566
+ * }, handler);
1567
+ * ```
1568
+ */ const SEQUENTIAL_THINKING_TOOL = {
1569
+ name: 'sequentialthinking_tools',
1570
+ description: TOOL_DESCRIPTION,
1571
+ inputSchema: {}
1572
+ };
1573
+ /**
1574
+ * Valibot schema for validating JSON-RPC 2.0 request messages.
1575
+ *
1576
+ * Validates that a JSON-RPC request has:
1577
+ * - A jsonrpc version (must be "2.0")
1578
+ * - A method name (string)
1579
+ * - Optional params (object or array)
1580
+ * - Optional id (string, number, or null for notifications)
1581
+ *
1582
+ * @example
1583
+ * ```typescript
1584
+ * import { safeParse } from 'valibot';
1585
+ * import { JsonRpcRequestSchema } from './schema.js';
1586
+ *
1587
+ * const result = safeParse(JsonRpcRequestSchema, {
1588
+ * jsonrpc: '2.0',
1589
+ * method: 'tools/list',
1590
+ * id: 1
1591
+ * });
1592
+ * ```
1593
+ */ const JsonRpcRequestSchema = valibot__rspack_import_0.object({
1594
+ jsonrpc: valibot__rspack_import_0.pipe(valibot__rspack_import_0.string(), valibot__rspack_import_0.literal('2.0'), valibot__rspack_import_0.description('JSON-RPC protocol version (must be "2.0")')),
1595
+ method: valibot__rspack_import_0.pipe(valibot__rspack_import_0.string(), valibot__rspack_import_0.minLength(1), valibot__rspack_import_0.description('Method name to invoke')),
1596
+ params: valibot__rspack_import_0.optional(valibot__rspack_import_0.pipe(valibot__rspack_import_0.union([
1597
+ valibot__rspack_import_0.object({}),
1598
+ valibot__rspack_import_0.array(valibot__rspack_import_0.unknown())
1599
+ ]), valibot__rspack_import_0.description('Method parameters (object or array)'))),
1600
+ id: valibot__rspack_import_0.optional(valibot__rspack_import_0.pipe(valibot__rspack_import_0.union([
1601
+ valibot__rspack_import_0.string(),
1602
+ valibot__rspack_import_0.number(),
1603
+ valibot__rspack_import_0["null"]()
1604
+ ]), valibot__rspack_import_0.description('Request ID (omit for notifications)')))
1605
+ });
1606
+ /**
1607
+ * Schema for {@link EdgeKind} — the semantic relationship between two thoughts.
1608
+ */ const EdgeKindSchema = valibot__rspack_import_0.union([
1609
+ valibot__rspack_import_0.literal('sequence'),
1610
+ valibot__rspack_import_0.literal('branch'),
1611
+ valibot__rspack_import_0.literal('merge'),
1612
+ valibot__rspack_import_0.literal('verifies'),
1613
+ valibot__rspack_import_0.literal('critiques'),
1614
+ valibot__rspack_import_0.literal('derives_from'),
1615
+ valibot__rspack_import_0.literal('tool_invocation'),
1616
+ valibot__rspack_import_0.literal('revises')
1617
+ ]);
1618
+ /**
1619
+ * Schema for {@link Edge} — a directed edge in the thought DAG.
1620
+ */ const EdgeSchema = valibot__rspack_import_0.object({
1621
+ id: valibot__rspack_import_0.pipe(valibot__rspack_import_0.string(), valibot__rspack_import_0.minLength(1), valibot__rspack_import_0.maxLength(30)),
1622
+ from: valibot__rspack_import_0.pipe(valibot__rspack_import_0.string(), valibot__rspack_import_0.minLength(1), valibot__rspack_import_0.maxLength(30)),
1623
+ to: valibot__rspack_import_0.pipe(valibot__rspack_import_0.string(), valibot__rspack_import_0.minLength(1), valibot__rspack_import_0.maxLength(30)),
1624
+ kind: EdgeKindSchema,
1625
+ sessionId: valibot__rspack_import_0.pipe(valibot__rspack_import_0.string(), valibot__rspack_import_0.minLength(1)),
1626
+ createdAt: valibot__rspack_import_0.number(),
1627
+ metadata: valibot__rspack_import_0.optional(valibot__rspack_import_0.record(valibot__rspack_import_0.string(), valibot__rspack_import_0.unknown()))
1628
+ });
1629
+
1630
+
1631
+ },
1632
+ 419(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
1633
+
1634
+ // EXPORTS
1635
+ __webpack_require__.d(__webpack_exports__, {
1636
+ j: () => (/* binding */ BaseTransport)
1637
+ });
1638
+
1639
+ // EXTERNAL MODULE: external "node:crypto"
1640
+ var external_node_crypto_ = __webpack_require__(561);
1641
+ ;// CONCATENATED MODULE: ./src/core/ids.ts
1642
+ /**
1643
+ * Unique identifier generation utilities for thoughts and edges.
1644
+ *
1645
+ * @module core/ids
1646
+ */
1647
+ /**
1648
+ * Generate a unique lexicographically-sortable identifier.
1649
+ *
1650
+ * Format: 8-char base36 timestamp + 20-char hex random (10 random bytes).
1651
+ * Result is up to 28 characters, sortable by creation time.
1652
+ *
1653
+ * @returns A unique string identifier.
1654
+ *
1655
+ * @example
1656
+ * ```typescript
1657
+ * const id = generateUlid(); // '01h2k3m400a1b2c3d4e5f6...'
1658
+ * ```
1659
+ */ function generateUlid() {
1660
+ const timestamp = Date.now().toString(36).padStart(8, '0');
1661
+ const random = crypto.randomBytes(10).toString('hex');
1662
+ return `${timestamp}${random}`;
1663
+ }
1664
+ /**
1665
+ * Valid session ID pattern: alphanumeric, hyphens, underscores.
1666
+ *
1667
+ * Length is enforced separately via {@link MAX_SESSION_ID_LENGTH}.
1668
+ * Same character set as branch IDs.
1669
+ */ const SESSION_ID_PATTERN = /^[a-zA-Z0-9_-]+$/;
1670
+ /**
1671
+ * Maximum session ID length (in characters).
1672
+ *
1673
+ * Allows compound identifiers (e.g. `user-123_task-abc`).
1674
+ */ const MAX_SESSION_ID_LENGTH = 100;
1675
+
1676
+ ;// CONCATENATED MODULE: ./src/transport/BaseTransport.ts
1677
+ /**
1678
+ * Base transport implementation.
1679
+ *
1680
+ * This class provides shared functionality for all transport implementations,
1681
+ * including session validation, rate limiting, CORS handling, and IP extraction.
1682
+ *
1683
+ * @remarks
1684
+ * **Security Features:**
1685
+ * - Session ID validation (alphanumeric, max 64 chars)
1686
+ * - Query parameter sanitization (whitelist allowed keys)
1687
+ * - Rate limiting per IP (configurable, default 100 req/min)
1688
+ * - CORS origin validation
1689
+ *
1690
+ * **Rate Limiting:**
1691
+ * - Tracks requests per IP address within a time window
1692
+ * - Returns 429 Too Many Requests when limit exceeded
1693
+ * - Can be disabled via `enableRateLimit: false`
1694
+ */
1695
+ /**
1696
+ * No-op logger that does nothing. Used when no logger is provided.
1697
+ */ class NoopLogger {
1698
+ _level = 'info';
1699
+ info(_message, _meta) {}
1700
+ warn(_message, _meta) {}
1701
+ error(_message, _meta) {}
1702
+ debug(_message, _meta) {}
1703
+ setLevel(level) {
1704
+ this._level = level;
1705
+ }
1706
+ getLevel() {
1707
+ return this._level;
1708
+ }
1709
+ }
1710
+ /**
1711
+ * Allowed query parameter names (whitelist for security).
1712
+ */ const ALLOWED_QUERY_PARAMS = new Set([
1713
+ 'session',
1714
+ 'sessionId',
1715
+ 'client',
1716
+ 'clientId'
1717
+ ]);
1718
+ /**
1719
+ * Rate limit settings (requests per minute per IP).
1720
+ */ const RATE_LIMIT_REQUESTS = 100;
1721
+ const RATE_LIMIT_WINDOW_MS = 60 * 1000; // 1 minute
1722
+ class BaseTransport {
1723
+ _port;
1724
+ _host;
1725
+ _corsOrigin;
1726
+ _enableCors;
1727
+ _rateLimitEnabled;
1728
+ _maxRequestsPerMinute;
1729
+ _allowedHosts;
1730
+ _rateLimitMap = new Map();
1731
+ _rateLimitCleanupIntervalId = null;
1732
+ _wasHostExplicitlySet;
1733
+ /** Shutdown state for graceful shutdown. */ _isShuttingDown = false;
1734
+ _logger;
1735
+ _healthChecker;
1736
+ constructor(options = {}){
1737
+ this._port = options.port ?? 9108;
1738
+ this._host = options.host ?? '127.0.0.1';
1739
+ this._wasHostExplicitlySet = options.host !== undefined;
1740
+ this._corsOrigin = options.corsOrigin ?? '*';
1741
+ this._enableCors = options.enableCors ?? true;
1742
+ this._rateLimitEnabled = options.enableRateLimit ?? true;
1743
+ this._maxRequestsPerMinute = options.maxRequestsPerMinute ?? RATE_LIMIT_REQUESTS;
1744
+ this._allowedHosts = this._buildAllowedHosts(options.allowedHosts);
1745
+ this._isShuttingDown = false;
1746
+ this._logger = options.logger ?? new NoopLogger();
1747
+ this._healthChecker = options.healthChecker ?? null;
1748
+ if (this._rateLimitEnabled) {
1749
+ this._startRateLimitCleanup();
1750
+ }
1751
+ }
1752
+ /**
1753
+ * Get the server URL with localhost substitution for default host.
1754
+ */ get serverUrl() {
1755
+ const host = !this._wasHostExplicitlySet && this._host === '127.0.0.1' ? 'localhost' : this._host;
1756
+ return `http://${host}:${this._port}`;
1757
+ }
1758
+ /**
1759
+ * Validate session ID format.
1760
+ *
1761
+ * @param sessionId - The session ID to validate
1762
+ * @returns true if valid, false otherwise
1763
+ */ validateSessionId(sessionId) {
1764
+ if (sessionId.length > MAX_SESSION_ID_LENGTH) {
1765
+ return false;
1766
+ }
1767
+ return SESSION_ID_PATTERN.test(sessionId);
1768
+ }
1769
+ /**
1770
+ * Sanitize query parameters by removing any not in whitelist.
1771
+ *
1772
+ * @param url - The URL object containing query parameters
1773
+ * @returns A sanitized record of allowed query parameters
1774
+ */ sanitizeQueryParams(url) {
1775
+ const sanitized = {};
1776
+ for (const [key, value] of url.searchParams.entries()){
1777
+ if (ALLOWED_QUERY_PARAMS.has(key)) {
1778
+ sanitized[key] = value;
1779
+ }
1780
+ }
1781
+ return sanitized;
1782
+ }
1783
+ /**
1784
+ * Check rate limit for a given IP address.
1785
+ *
1786
+ * @param ip - The IP address to check
1787
+ * @returns true if rate limit exceeded, false otherwise
1788
+ */ checkRateLimit(ip) {
1789
+ if (!this._rateLimitEnabled) {
1790
+ return false;
1791
+ }
1792
+ const now = Date.now();
1793
+ this._cleanupExpiredRateLimitEntries(now);
1794
+ const record = this._rateLimitMap.get(ip);
1795
+ if (!record || now > record.resetTime) {
1796
+ this._rateLimitMap.set(ip, {
1797
+ count: 1,
1798
+ resetTime: now + RATE_LIMIT_WINDOW_MS
1799
+ });
1800
+ return false;
1801
+ }
1802
+ if (record.count >= this._maxRequestsPerMinute) {
1803
+ return true; // Rate limit exceeded
1804
+ }
1805
+ record.count++;
1806
+ return false;
1807
+ }
1808
+ _cleanupExpiredRateLimitEntries(now = Date.now()) {
1809
+ for (const [ip, record] of this._rateLimitMap.entries()){
1810
+ if (record.resetTime <= now) {
1811
+ this._rateLimitMap.delete(ip);
1812
+ }
1813
+ }
1814
+ }
1815
+ _startRateLimitCleanup() {
1816
+ if (this._rateLimitCleanupIntervalId !== null) {
1817
+ clearInterval(this._rateLimitCleanupIntervalId);
1818
+ }
1819
+ this._rateLimitCleanupIntervalId = setInterval(()=>{
1820
+ this._cleanupExpiredRateLimitEntries();
1821
+ }, RATE_LIMIT_WINDOW_MS);
1822
+ }
1823
+ _stopRateLimitCleanup() {
1824
+ if (this._rateLimitCleanupIntervalId !== null) {
1825
+ clearInterval(this._rateLimitCleanupIntervalId);
1826
+ this._rateLimitCleanupIntervalId = null;
1827
+ }
1828
+ }
1829
+ /**
1830
+ * Get client IP address from request.
1831
+ *
1832
+ * @param req - The incoming request
1833
+ * @returns The client IP address
1834
+ */ getClientIp(req) {
1835
+ const forwardedFor = req.headers['x-forwarded-for'];
1836
+ if (forwardedFor && typeof forwardedFor === 'string') {
1837
+ return forwardedFor.split(',')[0].trim();
1838
+ }
1839
+ const remoteAddress = req.socket.remoteAddress;
1840
+ return remoteAddress || 'unknown';
1841
+ }
1842
+ /**
1843
+ * Validate CORS origin from request headers.
1844
+ *
1845
+ * @param req - The incoming request
1846
+ * @returns true if origin is valid, false otherwise
1847
+ */ validateCorsOrigin(req) {
1848
+ if (this._corsOrigin === '*') {
1849
+ return true;
1850
+ }
1851
+ const origin = req.headers.origin;
1852
+ if (!origin) {
1853
+ return true; // No origin header is acceptable
1854
+ }
1855
+ // Exact match
1856
+ if (this._corsOrigin === origin) {
1857
+ return true;
1858
+ }
1859
+ // Check if configured origin is a wildcard pattern
1860
+ if (this._corsOrigin.includes('*')) {
1861
+ // Escape all regex metacharacters EXCEPT *,
1862
+ // then replace * with a hostname-safe pattern (alphanumeric, hyphens, dots)
1863
+ const escaped = this._corsOrigin.replace(/[.+?^${}()|[\]\\]/g, '\\$&') // escape metacharacters (not *)
1864
+ .replace(/\*/g, '[a-zA-Z0-9.-]*'); // * matches valid hostname chars only
1865
+ const regex = new RegExp(`^${escaped}$`);
1866
+ return regex.test(origin);
1867
+ }
1868
+ return false;
1869
+ }
1870
+ /**
1871
+ * Set CORS headers on response.
1872
+ *
1873
+ * @param res - The server response
1874
+ */ setCorsHeaders(res) {
1875
+ if (this._enableCors) {
1876
+ res.setHeader('Access-Control-Allow-Origin', this._corsOrigin);
1877
+ res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
1878
+ res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
1879
+ }
1880
+ }
1881
+ validateHostHeader(req) {
1882
+ const rawHost = req.headers.host;
1883
+ if (!rawHost) {
1884
+ return true;
1885
+ }
1886
+ const hostWithoutPort = rawHost.split(':')[0].trim().toLowerCase();
1887
+ if (!hostWithoutPort) {
1888
+ return false;
1889
+ }
1890
+ if (this._allowedHosts.size === 0) {
1891
+ return true;
1892
+ }
1893
+ return this._allowedHosts.has(hostWithoutPort);
1894
+ }
1895
+ _buildAllowedHosts(configuredHosts) {
1896
+ if (configuredHosts && configuredHosts.length > 0) {
1897
+ return new Set(configuredHosts.map((host)=>host.toLowerCase().trim()).filter(Boolean));
1898
+ }
1899
+ const boundHost = this._host.toLowerCase();
1900
+ const localHosts = [
1901
+ 'localhost',
1902
+ '127.0.0.1',
1903
+ '::1'
1904
+ ];
1905
+ if (localHosts.includes(boundHost)) {
1906
+ return new Set(localHosts);
1907
+ }
1908
+ if (boundHost === '0.0.0.0' || boundHost === '::') {
1909
+ return new Set(localHosts);
1910
+ }
1911
+ return new Set([
1912
+ boundHost
1913
+ ]);
1914
+ }
1915
+ /**
1916
+ * Log a message using the configured logger.
1917
+ *
1918
+ * @param level - Log level
1919
+ * @param message - Message to log
1920
+ * @param meta - Optional metadata
1921
+ */ log(level, message, meta) {
1922
+ if (level === 'info') {
1923
+ this._logger.info(message, meta);
1924
+ } else if (level === 'warn') {
1925
+ this._logger.warn(message, meta);
1926
+ } else {
1927
+ this._logger.error(message, meta);
1928
+ }
1929
+ }
1930
+ /**
1931
+ * Check if transport is shutting down.
1932
+ * @returns true if in shutdown phase
1933
+ */ get isShuttingDown() {
1934
+ return this._isShuttingDown;
1935
+ }
1936
+ /**
1937
+ * Handle GET /health endpoint — liveness check.
1938
+ *
1939
+ * Builds a standard health response with optional liveness data from the health checker.
1940
+ * Transports can pass extra data (e.g. client counts, session info).
1941
+ *
1942
+ * @param res - The server response
1943
+ * @param extraData - Optional additional health metadata
1944
+ */ handleHealthEndpoint(res, extraData) {
1945
+ const healthData = {
1946
+ status: 'healthy',
1947
+ ...extraData
1948
+ };
1949
+ if (this._healthChecker) {
1950
+ const liveness = this._healthChecker.checkLiveness();
1951
+ healthData.liveness = liveness;
1952
+ }
1953
+ res.writeHead(200, {
1954
+ 'Content-Type': 'application/json'
1955
+ });
1956
+ res.end(JSON.stringify(healthData));
1957
+ }
1958
+ /**
1959
+ * Handle GET /ready endpoint — readiness check.
1960
+ *
1961
+ * Delegates to the health checker if available, otherwise returns a default OK response.
1962
+ *
1963
+ * @param res - The server response
1964
+ */ async handleReadinessEndpoint(res) {
1965
+ if (this._healthChecker) {
1966
+ const readiness = await this._healthChecker.checkReadiness();
1967
+ const statusCode = readiness.status === 'ok' ? 200 : 503;
1968
+ res.writeHead(statusCode, {
1969
+ 'Content-Type': 'application/json'
1970
+ });
1971
+ res.end(JSON.stringify(readiness));
1972
+ } else {
1973
+ res.writeHead(200, {
1974
+ 'Content-Type': 'application/json'
1975
+ });
1976
+ res.end(JSON.stringify({
1977
+ status: 'ok',
1978
+ timestamp: new Date().toISOString(),
1979
+ components: {}
1980
+ }));
1981
+ }
1982
+ }
1983
+ /**
1984
+ * Handle GET /metrics endpoint — Prometheus metrics.
1985
+ *
1986
+ * Returns 404 if no metrics provider is configured.
1987
+ *
1988
+ * @param res - The server response
1989
+ * @param metricsProvider - Function that returns Prometheus-format metrics text
1990
+ */ handleMetricsEndpoint(res, metricsProvider) {
1991
+ if (!metricsProvider) {
1992
+ res.writeHead(404, {
1993
+ 'Content-Type': 'text/plain'
1994
+ });
1995
+ res.end('Not Found');
1996
+ return;
1997
+ }
1998
+ res.writeHead(200, {
1999
+ 'Content-Type': 'text/plain; version=0.0.4; charset=utf-8'
2000
+ });
2001
+ res.end(metricsProvider());
2002
+ }
2003
+ }
2004
+
2005
+
2006
+ },
2007
+ 390(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
2008
+ __webpack_require__.d(__webpack_exports__, {
2009
+ SseTransport: () => (SseTransport)
2010
+ });
2011
+ /* import */ var node_http__rspack_import_0 = __webpack_require__(316);
2012
+ /* import */ var node_crypto__rspack_import_1 = __webpack_require__(561);
2013
+ /* import */ var node_url__rspack_import_2 = __webpack_require__(61);
2014
+ /* import */ var valibot__rspack_import_3 = __webpack_require__(821);
2015
+ /* import */ var _schema_js__rspack_import_4 = __webpack_require__(613);
2016
+ /* import */ var _BaseTransport_js__rspack_import_5 = __webpack_require__(419);
2017
+ /* import */ var _context_RequestContext_js__rspack_import_6 = __webpack_require__(923);
2018
+ /**
2019
+ * SSE (Server-Sent Events) Transport implementation.
2020
+ *
2021
+ * This transport allows multiple concurrent connections over HTTP using Server-Sent Events,
2022
+ * enabling multi-user scenarios and horizontal scaling.
2023
+ *
2024
+ * When a ConnectionPool is provided, each SSE client gets an isolated session with its own
2025
+ * thought history. Without a pool, all clients share a single server instance (backward compatible).
2026
+ *
2027
+ * @example
2028
+ * ```typescript
2029
+ * const transport = new SseTransport({
2030
+ * port: 3000,
2031
+ * host: 'localhost'
2032
+ * });
2033
+ * await transport.connect(server);
2034
+ * ```
2035
+ */
2036
+
2037
+
2038
+
2039
+
2040
+
2041
+
2042
+ /**
2043
+ * SSE Transport for MCP server over HTTP.
2044
+ *
2045
+ * This transport uses Server-Sent Events (SSE) to communicate with clients,
2046
+ * allowing multiple concurrent connections and web-based clients.
2047
+ *
2048
+ * @remarks
2049
+ * **Security Features:**
2050
+ * - Session ID validation (alphanumeric, max 64 chars)
2051
+ * - Query parameter sanitization (whitelist allowed keys)
2052
+ * - Rate limiting per IP (configurable, default 100 req/min)
2053
+ * - CORS origin validation
2054
+ *
2055
+ * **Rate Limiting:**
2056
+ * - Tracks requests per IP address within a time window
2057
+ * - Returns 429 Too Many Requests when limit exceeded
2058
+ * - Can be disabled via `enableRateLimit: false`
2059
+ */ class SseTransport extends _BaseTransport_js__rspack_import_5/* .BaseTransport */.j {
2060
+ get kind() {
2061
+ return 'sse';
2062
+ }
2063
+ _server;
2064
+ _path;
2065
+ _clients = new Set();
2066
+ _clientSessionMap = new Map();
2067
+ _messageQueue = new Map();
2068
+ _metrics;
2069
+ _connectionPool;
2070
+ constructor(options = {}){
2071
+ super(options);
2072
+ this._path = options.path ?? '/sse';
2073
+ this._metrics = options.metrics;
2074
+ this._connectionPool = options.connectionPool;
2075
+ this._updateActiveConnectionsMetric();
2076
+ this._server = (0,node_http__rspack_import_0.createServer)((req, res)=>this._handleRequest(req, res));
2077
+ }
2078
+ /**
2079
+ * Connect MCP server to this transport.
2080
+ *
2081
+ * @param mcpServer - The MCP server instance
2082
+ */ async connect(mcpServer) {
2083
+ this._mcpServer = mcpServer;
2084
+ return new Promise((resolve)=>{
2085
+ this._server.listen(this._port, this._host, ()=>{
2086
+ this.log('info', `SSE transport listening on http://${this._host}:${this._port}`);
2087
+ resolve();
2088
+ });
2089
+ });
2090
+ }
2091
+ _mcpServer = null;
2092
+ /**
2093
+ * Handle incoming HTTP requests
2094
+ */ async _handleRequest(req, res) {
2095
+ const startTime = Date.now();
2096
+ const requestPath = req.url || '/';
2097
+ const requestMethod = req.method || 'GET';
2098
+ this._metrics?.counter('http_requests_total', 1, {
2099
+ transport: 'sse',
2100
+ method: requestMethod,
2101
+ path: requestPath
2102
+ }, 'Total HTTP requests');
2103
+ res.once('finish', ()=>{
2104
+ const durationSeconds = (Date.now() - startTime) / 1000;
2105
+ this._metrics?.histogram('http_request_duration_seconds', durationSeconds, {
2106
+ transport: 'sse',
2107
+ path: requestPath
2108
+ });
2109
+ });
2110
+ if (!this.validateHostHeader(req)) {
2111
+ this._metrics?.counter('http_request_errors_total', 1, {
2112
+ transport: 'sse',
2113
+ error_type: 'forbidden'
2114
+ }, 'Total HTTP request errors');
2115
+ res.writeHead(403, {
2116
+ 'Content-Type': 'application/json'
2117
+ });
2118
+ res.end(JSON.stringify({
2119
+ error: 'Forbidden - invalid host header'
2120
+ }));
2121
+ return;
2122
+ }
2123
+ const url = new node_url__rspack_import_2.URL(req.url || '', `http://${req.headers.host}`);
2124
+ // Check rate limit first
2125
+ const clientIp = this.getClientIp(req);
2126
+ if (this.checkRateLimit(clientIp)) {
2127
+ this._metrics?.counter('http_request_errors_total', 1, {
2128
+ transport: 'sse',
2129
+ error_type: 'rate_limit'
2130
+ }, 'Total HTTP request errors');
2131
+ res.writeHead(429, {
2132
+ 'Content-Type': 'application/json',
2133
+ 'Retry-After': '60'
2134
+ });
2135
+ res.end(JSON.stringify({
2136
+ error: 'Too many requests'
2137
+ }));
2138
+ return;
2139
+ }
2140
+ // Validate CORS origin
2141
+ if (!this.validateCorsOrigin(req)) {
2142
+ this._metrics?.counter('http_request_errors_total', 1, {
2143
+ transport: 'sse',
2144
+ error_type: 'forbidden'
2145
+ }, 'Total HTTP request errors');
2146
+ res.writeHead(403, {
2147
+ 'Content-Type': 'application/json'
2148
+ });
2149
+ res.end(JSON.stringify({
2150
+ error: 'Forbidden - invalid origin'
2151
+ }));
2152
+ return;
2153
+ }
2154
+ // Set CORS headers
2155
+ this.setCorsHeaders(res);
2156
+ // Sanitize query parameters
2157
+ const sanitizedParams = this.sanitizeQueryParams(url);
2158
+ // Validate session ID if present
2159
+ if (sanitizedParams.session || sanitizedParams.sessionId) {
2160
+ const sessionId = sanitizedParams.session ?? sanitizedParams.sessionId;
2161
+ if (!this.validateSessionId(sessionId)) {
2162
+ this._metrics?.counter('http_request_errors_total', 1, {
2163
+ transport: 'sse',
2164
+ error_type: 'validation'
2165
+ }, 'Total HTTP request errors');
2166
+ res.writeHead(400, {
2167
+ 'Content-Type': 'application/json'
2168
+ });
2169
+ res.end(JSON.stringify({
2170
+ error: 'Invalid session ID format'
2171
+ }));
2172
+ return;
2173
+ }
2174
+ }
2175
+ // Handle CORS preflight
2176
+ if (this._enableCors && req.method === 'OPTIONS') {
2177
+ res.writeHead(204);
2178
+ res.end();
2179
+ return;
2180
+ }
2181
+ // Handle SSE endpoint
2182
+ if (url.pathname === this._path && req.method === 'GET') {
2183
+ await this._handleSseConnection(req, res, sanitizedParams);
2184
+ return;
2185
+ }
2186
+ // Handle message endpoint (for receiving messages from clients)
2187
+ if (url.pathname === `${this._path}/message` && req.method === 'POST') {
2188
+ await this._handleMessage(req, res, sanitizedParams);
2189
+ return;
2190
+ }
2191
+ // Handle health check (liveness)
2192
+ if (url.pathname === '/health') {
2193
+ this._handleHealthCheck(res);
2194
+ return;
2195
+ }
2196
+ // Handle readiness check
2197
+ if (url.pathname === '/ready') {
2198
+ await this._handleReadinessCheck(res);
2199
+ return;
2200
+ }
2201
+ // 404 for unknown paths
2202
+ res.writeHead(404, {
2203
+ 'Content-Type': 'text/plain'
2204
+ });
2205
+ res.end('Not Found');
2206
+ }
2207
+ /**
2208
+ * Handle health check (liveness) endpoint
2209
+ */ _handleHealthCheck(res) {
2210
+ const healthData = {
2211
+ status: 'healthy',
2212
+ clients: this._clients.size
2213
+ };
2214
+ if (this._connectionPool) {
2215
+ const poolStats = this._connectionPool.getStats();
2216
+ healthData.pool = poolStats;
2217
+ }
2218
+ if (this._healthChecker) {
2219
+ const liveness = this._healthChecker.checkLiveness();
2220
+ healthData.liveness = liveness;
2221
+ }
2222
+ res.writeHead(200, {
2223
+ 'Content-Type': 'application/json'
2224
+ });
2225
+ res.end(JSON.stringify(healthData));
2226
+ }
2227
+ /**
2228
+ * Handle readiness check endpoint
2229
+ */ async _handleReadinessCheck(res) {
2230
+ if (this._healthChecker) {
2231
+ const readiness = await this._healthChecker.checkReadiness();
2232
+ const statusCode = readiness.status === 'ok' ? 200 : 503;
2233
+ res.writeHead(statusCode, {
2234
+ 'Content-Type': 'application/json'
2235
+ });
2236
+ res.end(JSON.stringify(readiness));
2237
+ } else {
2238
+ res.writeHead(200, {
2239
+ 'Content-Type': 'application/json'
2240
+ });
2241
+ res.end(JSON.stringify({
2242
+ status: 'ok',
2243
+ timestamp: new Date().toISOString(),
2244
+ components: {}
2245
+ }));
2246
+ }
2247
+ }
2248
+ /**
2249
+ * Handle new SSE connection
2250
+ */ async _handleSseConnection(req, res, params) {
2251
+ // Set SSE headers
2252
+ res.writeHead(200, {
2253
+ 'Content-Type': 'text/event-stream',
2254
+ 'Cache-Control': 'no-cache',
2255
+ Connection: 'keep-alive'
2256
+ });
2257
+ // Resolve session ID when pool is active
2258
+ let sessionId;
2259
+ if (this._connectionPool) {
2260
+ const requestedSession = params.session ?? params.sessionId;
2261
+ if (requestedSession && this._connectionPool.getSessionInfo(requestedSession)) {
2262
+ sessionId = requestedSession;
2263
+ } else {
2264
+ try {
2265
+ sessionId = await this._connectionPool.createSession();
2266
+ } catch (error) {
2267
+ res.write(`event: error\n`);
2268
+ res.write(`data: ${JSON.stringify({
2269
+ error: error instanceof Error ? error.message : 'Failed to create session'
2270
+ })}\n\n`);
2271
+ res.end();
2272
+ return;
2273
+ }
2274
+ }
2275
+ this._clientSessionMap.set(res, sessionId);
2276
+ this._updatePoolMetrics();
2277
+ }
2278
+ // Send initial connection event
2279
+ const connectedPayload = {
2280
+ timestamp: Date.now()
2281
+ };
2282
+ if (sessionId) {
2283
+ connectedPayload.sessionId = sessionId;
2284
+ }
2285
+ this._sendSseEvent(res, 'connected', connectedPayload);
2286
+ // Add to clients
2287
+ this._clients.add(res);
2288
+ this._updateActiveConnectionsMetric();
2289
+ // Handle client disconnect
2290
+ req.on('close', ()=>{
2291
+ this._clients.delete(res);
2292
+ this._clientSessionMap.delete(res);
2293
+ this._updateActiveConnectionsMetric();
2294
+ });
2295
+ // Send any queued messages
2296
+ const clientId = this._generateClientId();
2297
+ const queued = this._messageQueue.get(clientId);
2298
+ if (queued) {
2299
+ for (const message of queued){
2300
+ this._sendSseEvent(res, 'message', message);
2301
+ }
2302
+ this._messageQueue.delete(clientId);
2303
+ }
2304
+ }
2305
+ /**
2306
+ * Handle incoming message from client
2307
+ */ async _handleMessage(req, res, _params) {
2308
+ let body = '';
2309
+ for await (const chunk of req){
2310
+ body += chunk.toString();
2311
+ }
2312
+ try {
2313
+ const jsonRpcRequest = JSON.parse(body);
2314
+ const parseResult = (0,valibot__rspack_import_3.safeParse)(_schema_js__rspack_import_4/* .JsonRpcRequestSchema */.Uv, jsonRpcRequest);
2315
+ if (!parseResult.success) {
2316
+ this._metrics?.counter('http_request_errors_total', 1, {
2317
+ transport: 'sse',
2318
+ error_type: 'validation'
2319
+ }, 'Total HTTP request errors');
2320
+ res.writeHead(200, {
2321
+ 'Content-Type': 'application/json'
2322
+ });
2323
+ res.end(JSON.stringify({
2324
+ jsonrpc: '2.0',
2325
+ id: jsonRpcRequest?.id ?? null,
2326
+ error: {
2327
+ code: -32600,
2328
+ message: 'Invalid Request',
2329
+ data: parseResult.issues
2330
+ }
2331
+ }));
2332
+ return;
2333
+ }
2334
+ // Process message through MCP server with owner context
2335
+ if (this._mcpServer) {
2336
+ const sessionId = this._clientSessionMap.get(res);
2337
+ const owner = sessionId ?? `sse-${(0,node_crypto__rspack_import_1.randomUUID)()}`;
2338
+ const response = await (0,_context_RequestContext_js__rspack_import_6/* .runWithContext */.Vo)({
2339
+ requestId: (0,node_crypto__rspack_import_1.randomUUID)(),
2340
+ owner
2341
+ }, ()=>this._mcpServer.receive(jsonRpcRequest, {
2342
+ sessionInfo: {}
2343
+ }));
2344
+ res.writeHead(200, {
2345
+ 'Content-Type': 'application/json'
2346
+ });
2347
+ if (response) {
2348
+ res.end(JSON.stringify(response));
2349
+ } else {
2350
+ res.end(JSON.stringify({
2351
+ jsonrpc: '2.0',
2352
+ id: jsonRpcRequest?.id ?? null,
2353
+ result: null
2354
+ }));
2355
+ }
2356
+ } else {
2357
+ this._metrics?.counter('http_request_errors_total', 1, {
2358
+ transport: 'sse',
2359
+ error_type: 'server_not_ready'
2360
+ }, 'Total HTTP request errors');
2361
+ res.writeHead(503, {
2362
+ 'Content-Type': 'application/json'
2363
+ });
2364
+ res.end(JSON.stringify({
2365
+ error: 'Server not ready'
2366
+ }));
2367
+ }
2368
+ } catch {
2369
+ this._metrics?.counter('http_request_errors_total', 1, {
2370
+ transport: 'sse',
2371
+ error_type: 'parse_error'
2372
+ }, 'Total HTTP request errors');
2373
+ res.writeHead(400, {
2374
+ 'Content-Type': 'application/json'
2375
+ });
2376
+ res.end(JSON.stringify({
2377
+ error: 'Invalid JSON'
2378
+ }));
2379
+ }
2380
+ }
2381
+ /**
2382
+ * Send an SSE event to a specific client
2383
+ */ _sendSseEvent(res, event, data) {
2384
+ try {
2385
+ res.write(`event: ${event}\n`);
2386
+ res.write(`data: ${JSON.stringify(data)}\n\n`);
2387
+ } catch {
2388
+ // Client disconnected
2389
+ this._clients.delete(res);
2390
+ this._updateActiveConnectionsMetric();
2391
+ }
2392
+ }
2393
+ _updateActiveConnectionsMetric() {
2394
+ this._metrics?.gauge('sse_active_connections', this._clients.size, {}, 'Current active SSE connections');
2395
+ }
2396
+ _updatePoolMetrics() {
2397
+ if (!this._connectionPool || !this._metrics) {
2398
+ return;
2399
+ }
2400
+ const stats = this._connectionPool.getStats();
2401
+ this._metrics.gauge('sse_pool_active_sessions', stats.activeSessions, {}, 'Active sessions in connection pool');
2402
+ this._metrics.gauge('sse_pool_total_sessions', stats.totalSessions, {}, 'Total sessions in connection pool');
2403
+ this._metrics.gauge('sse_pool_max_sessions', stats.maxSessions, {}, 'Maximum sessions in connection pool');
2404
+ }
2405
+ /**
2406
+ * Broadcast a message to all connected clients
2407
+ */ broadcast(event, data) {
2408
+ for (const client of this._clients){
2409
+ this._sendSseEvent(client, event, data);
2410
+ }
2411
+ }
2412
+ /**
2413
+ * Generate a unique client ID
2414
+ */ _generateClientId() {
2415
+ return `client_${Date.now()}_${Math.random().toString(36).substring(2, 11)}`;
2416
+ }
2417
+ /**
2418
+ * Get number of connected clients
2419
+ */ get clientCount() {
2420
+ return this._clients.size;
2421
+ }
2422
+ /**
2423
+ * Get the connection pool, if one was configured.
2424
+ */ get connectionPool() {
2425
+ return this._connectionPool;
2426
+ }
2427
+ /**
2428
+ * Stop the transport server with graceful shutdown.
2429
+ *
2430
+ * @param timeout - Maximum time to wait for requests to drain (not used for SSE)
2431
+ * @returns Promise that resolves when shutdown is complete
2432
+ */ async stop(_timeout) {
2433
+ this._isShuttingDown = true;
2434
+ this._stopRateLimitCleanup();
2435
+ // Terminate connection pool if present
2436
+ if (this._connectionPool) {
2437
+ await this._connectionPool.terminate();
2438
+ }
2439
+ return new Promise((resolve)=>{
2440
+ // Close all client connections
2441
+ for (const client of this._clients){
2442
+ try {
2443
+ client.end();
2444
+ } catch {
2445
+ // Ignore errors
2446
+ }
2447
+ }
2448
+ this._clients.clear();
2449
+ this._clientSessionMap.clear();
2450
+ this._updateActiveConnectionsMetric();
2451
+ // Close server
2452
+ this._server.close(()=>{
2453
+ this.log('info', 'SSE transport stopped');
2454
+ resolve();
2455
+ });
2456
+ });
2457
+ }
2458
+ }
2459
+ /**
2460
+ * Create an SSE transport with given options.
2461
+ *
2462
+ * @param options - Transport configuration
2463
+ * @returns A configured SSE transport
2464
+ *
2465
+ * @example
2466
+ * ```typescript
2467
+ * const transport = createSseTransport({ port: 3000 });
2468
+ * await transport.connect(mcpServer);
2469
+ * ```
2470
+ */ function createSseTransport(options = {}) {
2471
+ return new SseTransport(options);
2472
+ }
2473
+
2474
+
2475
+ },
2476
+ 34(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
2477
+
2478
+ // EXPORTS
2479
+ __webpack_require__.d(__webpack_exports__, {
2480
+ StreamableHttpTransport: () => (/* binding */ StreamableHttpTransport)
2481
+ });
2482
+
2483
+ // UNUSED EXPORTS: createStreamableHttpTransport
2484
+
2485
+ // EXTERNAL MODULE: external "node:crypto"
2486
+ var external_node_crypto_ = __webpack_require__(561);
2487
+ // EXTERNAL MODULE: external "node:http"
2488
+ var external_node_http_ = __webpack_require__(316);
2489
+ // EXTERNAL MODULE: external "valibot"
2490
+ var external_valibot_ = __webpack_require__(821);
2491
+ // EXTERNAL MODULE: ./src/errors.ts
2492
+ var errors = __webpack_require__(937);
2493
+ // EXTERNAL MODULE: ./src/schema.ts
2494
+ var schema = __webpack_require__(613);
2495
+ // EXTERNAL MODULE: ./src/transport/BaseTransport.ts + 1 modules
2496
+ var BaseTransport = __webpack_require__(419);
2497
+ ;// CONCATENATED MODULE: ./src/transport/HttpHelpers.ts
2498
+ /**
2499
+ * Shared HTTP helper utilities for MCP transport implementations.
2500
+ *
2501
+ * Centralizes JSON-RPC response formatting, request body reading,
2502
+ * and common HTTP response patterns to eliminate duplication across
2503
+ * HttpTransport, StreamableHttpTransport, and SseTransport.
2504
+ *
2505
+ * @module transport/HttpHelpers
2506
+ */ /**
2507
+ * Send a JSON-RPC 2.0 error response.
2508
+ *
2509
+ * Standardizes error response formatting across all transport implementations.
2510
+ * All JSON-RPC errors use the standard `{ jsonrpc, id, error }` shape.
2511
+ *
2512
+ * @param res - The server response to write to
2513
+ * @param statusCode - HTTP status code (e.g. 400, 403, 429, 500)
2514
+ * @param code - JSON-RPC error code (e.g. -32700, -32600, -32603)
2515
+ * @param message - Human-readable error message
2516
+ * @param id - Optional JSON-RPC request ID (defaults to null)
2517
+ * @param data - Optional additional error data
2518
+ */ function sendJsonRpcError(res, statusCode, code, message, id = null, data) {
2519
+ const body = {
2520
+ jsonrpc: '2.0',
2521
+ id,
2522
+ error: {
2523
+ code,
2524
+ message
2525
+ }
2526
+ };
2527
+ if (data !== undefined) {
2528
+ body.error.data = data;
2529
+ }
2530
+ res.writeHead(statusCode, {
2531
+ 'Content-Type': 'application/json'
2532
+ });
2533
+ res.end(JSON.stringify(body));
2534
+ }
2535
+ /**
2536
+ * Send a JSON-RPC 2.0 success response.
2537
+ *
2538
+ * @param res - The server response to write to
2539
+ * @param response - The JSON-RPC response object to send
2540
+ * @param statusCode - HTTP status code (default: 200)
2541
+ * @param headers - Optional additional response headers
2542
+ */ function sendJsonRpcResponse(res, response, statusCode = 200, headers = {}) {
2543
+ const defaultHeaders = {
2544
+ 'Content-Type': 'application/json'
2545
+ };
2546
+ res.writeHead(statusCode, {
2547
+ ...defaultHeaders,
2548
+ ...headers
2549
+ });
2550
+ res.end(JSON.stringify(response));
2551
+ }
2552
+ /**
2553
+ * Send a CORS preflight (OPTIONS) response.
2554
+ *
2555
+ * @param res - The server response to write to
2556
+ * @param extraAllowHeaders - Optional extra Access-Control-Allow-Headers values
2557
+ */ function sendCorsPreflight(res, extraAllowHeaders) {
2558
+ if (extraAllowHeaders && extraAllowHeaders.length > 0) {
2559
+ res.setHeader('Access-Control-Allow-Headers', `Content-Type, ${extraAllowHeaders.join(', ')}`);
2560
+ }
2561
+ res.writeHead(204);
2562
+ res.end();
2563
+ }
2564
+ /**
2565
+ * Read the full request body with optional size limit enforcement.
2566
+ *
2567
+ * Streams the request body chunks, tracking total size.
2568
+ * If the body exceeds `maxBodySize`, reading stops and `null` is returned
2569
+ * to indicate the payload is too large.
2570
+ *
2571
+ * @param req - The incoming HTTP request
2572
+ * @param maxBodySize - Maximum allowed body size in bytes (0 = unlimited)
2573
+ * @returns The body string, or `null` if the body exceeded the size limit
2574
+ */ async function readRequestBody(req, maxBodySize) {
2575
+ let body = '';
2576
+ let bodySize = 0;
2577
+ for await (const chunk of req){
2578
+ const chunkStr = typeof chunk === 'string' ? chunk : chunk.toString();
2579
+ bodySize += chunkStr.length;
2580
+ if (maxBodySize > 0 && bodySize > maxBodySize) {
2581
+ return null;
2582
+ }
2583
+ body += chunkStr;
2584
+ }
2585
+ return body;
2586
+ }
2587
+
2588
+ // EXTERNAL MODULE: ./src/context/RequestContext.ts + 1 modules
2589
+ var RequestContext = __webpack_require__(923);
2590
+ ;// CONCATENATED MODULE: ./src/transport/StreamableHttpTransport.ts
2591
+ /**
2592
+ * Streamable HTTP Transport implementation (MCP spec recommended transport).
2593
+ *
2594
+ * This transport implements the MCP Streamable HTTP specification, which replaces
2595
+ * the deprecated SSE transport as the recommended HTTP-based transport since March 2025.
2596
+ *
2597
+ * Key features:
2598
+ * - POST /mcp for JSON-RPC requests (main MCP endpoint)
2599
+ * - GET /mcp for optional SSE server-to-client notifications
2600
+ * - Session management via Mcp-Session-Id header
2601
+ * - Supports both stateful (session-based) and stateless (per-request) modes
2602
+ * - Health endpoints (/health, /ready)
2603
+ *
2604
+ * @example
2605
+ * ```typescript
2606
+ * const transport = new StreamableHttpTransport({
2607
+ * port: 3000,
2608
+ * host: 'localhost',
2609
+ * stateful: true,
2610
+ * });
2611
+ * await transport.connect(server);
2612
+ * ```
2613
+ */
2614
+
2615
+
2616
+
2617
+
2618
+
2619
+
2620
+
2621
+ /**
2622
+ * Streamable HTTP Transport for MCP server.
2623
+ *
2624
+ * This transport implements the MCP Streamable HTTP specification,
2625
+ * providing JSON-RPC over HTTP with optional session management
2626
+ * and server-to-client SSE notification streams.
2627
+ *
2628
+ * @remarks
2629
+ * **Security Features (inherited from BaseTransport):**
2630
+ * - Session ID validation (alphanumeric, max 64 chars)
2631
+ * - Query parameter sanitization (whitelist allowed keys)
2632
+ * - Rate limiting per IP (configurable, default 100 req/min)
2633
+ * - CORS origin validation
2634
+ * - Host header validation
2635
+ *
2636
+ * **MCP Streamable HTTP Spec Compliance:**
2637
+ * - POST /mcp — JSON-RPC method calls
2638
+ * - GET /mcp — SSE notification stream (server-to-client)
2639
+ * - Mcp-Session-Id header for session management
2640
+ * - Content-Type: application/json for JSON-RPC responses
2641
+ * - Content-Type: text/event-stream for SSE notification streams
2642
+ *
2643
+ * **HTTP Status Code Mapping:**
2644
+ * - 200: Success (JSON-RPC response or SSE stream)
2645
+ * - 202: Accepted (JSON-RPC notification, no response body)
2646
+ * - 204: CORS Preflight (empty body)
2647
+ * - 400: Bad Request (invalid JSON, invalid session ID)
2648
+ * - 403: Forbidden (invalid CORS, invalid host)
2649
+ * - 404: Not Found
2650
+ * - 405: Method Not Allowed
2651
+ * - 413: Payload Too Large
2652
+ * - 429: Too Many Requests
2653
+ * - 500: Internal Server Error
2654
+ * - 503: Server Not Ready / Shutting Down
2655
+ */ class StreamableHttpTransport extends BaseTransport/* .BaseTransport */.j {
2656
+ get kind() {
2657
+ return 'streamable-http';
2658
+ }
2659
+ _server = null;
2660
+ _mcpServer = null;
2661
+ _path;
2662
+ _stateful;
2663
+ _sessionIdGenerator;
2664
+ _sessions = new Map();
2665
+ _requestCount = 0;
2666
+ _activeRequests = 0;
2667
+ _bodySizeLimitEnabled;
2668
+ _maxBodySize;
2669
+ _requestTimeout;
2670
+ _metrics;
2671
+ _metricsProvider;
2672
+ constructor(options = {}){
2673
+ super(options);
2674
+ this._path = options.path ?? '/mcp';
2675
+ this._stateful = options.stateful ?? true;
2676
+ this._sessionIdGenerator = options.sessionIdGenerator ?? (()=>(0,external_node_crypto_.randomUUID)());
2677
+ this._bodySizeLimitEnabled = options.enableBodySizeLimit ?? true;
2678
+ this._maxBodySize = options.maxBodySize ?? 10 * 1024 * 1024;
2679
+ this._requestTimeout = options.requestTimeout ?? 30000;
2680
+ this._metrics = options.metrics;
2681
+ this._metricsProvider = options.metricsProvider ?? null;
2682
+ }
2683
+ /**
2684
+ * Get number of active sessions (stateful) or active requests (stateless).
2685
+ */ get clientCount() {
2686
+ return this._stateful ? this._sessions.size : this._activeRequests;
2687
+ }
2688
+ /**
2689
+ * Get the total number of requests handled.
2690
+ */ get requestCount() {
2691
+ return this._requestCount;
2692
+ }
2693
+ /**
2694
+ * Connects MCP server to this transport and starts listening.
2695
+ */ async connect(mcpServer) {
2696
+ this._mcpServer = mcpServer;
2697
+ this._server = (0,external_node_http_.createServer)((req, res)=>this._handleRequest(req, res));
2698
+ return new Promise((resolve)=>{
2699
+ this._server.listen(this._port, this._host, ()=>{
2700
+ this.log('info', `Streamable HTTP transport listening on http://${this._host}:${this._port}`);
2701
+ resolve();
2702
+ });
2703
+ });
2704
+ }
2705
+ /**
2706
+ * Route and handle incoming HTTP requests.
2707
+ */ async _handleRequest(req, res) {
2708
+ const startTime = Date.now();
2709
+ this._metrics?.counter('streamable_http_requests_total', 1, {}, 'Total Streamable HTTP transport requests');
2710
+ res.once('finish', ()=>{
2711
+ const durationSeconds = (Date.now() - startTime) / 1000;
2712
+ this._metrics?.histogram('streamable_http_request_duration_seconds', durationSeconds, {});
2713
+ });
2714
+ // Host validation
2715
+ if (!this.validateHostHeader(req)) {
2716
+ this._sendJsonRpcError(res, 403, -32000, 'Forbidden - invalid host header');
2717
+ return;
2718
+ }
2719
+ // Shutdown check
2720
+ if (this.isShuttingDown) {
2721
+ this._sendJsonRpcError(res, 503, -32603, 'Server is shutting down');
2722
+ return;
2723
+ }
2724
+ // Rate limiting
2725
+ const clientIp = this.getClientIp(req);
2726
+ if (this.checkRateLimit(clientIp)) {
2727
+ res.setHeader('Retry-After', '60');
2728
+ this._sendJsonRpcError(res, 429, -32000, 'Too many requests');
2729
+ return;
2730
+ }
2731
+ // CORS validation
2732
+ if (!this.validateCorsOrigin(req)) {
2733
+ this._sendJsonRpcError(res, 403, -32000, 'Forbidden - invalid origin');
2734
+ return;
2735
+ }
2736
+ this.setCorsHeaders(res);
2737
+ // CORS preflight
2738
+ if (req.method === 'OPTIONS') {
2739
+ res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Mcp-Session-Id');
2740
+ res.writeHead(204);
2741
+ res.end();
2742
+ return;
2743
+ }
2744
+ // Parse URL path
2745
+ const urlPath = req.url?.split('?')[0] ?? '/';
2746
+ // Metrics endpoint
2747
+ if (req.method === 'GET' && urlPath === '/metrics') {
2748
+ this._handleMetrics(res);
2749
+ return;
2750
+ }
2751
+ // Health check (liveness)
2752
+ if (req.method === 'GET' && urlPath === '/health') {
2753
+ this._handleHealthCheck(res);
2754
+ return;
2755
+ }
2756
+ // Readiness check
2757
+ if (req.method === 'GET' && urlPath === '/ready') {
2758
+ await this._handleReadinessCheck(res);
2759
+ return;
2760
+ }
2761
+ // MCP endpoint routing
2762
+ if (urlPath === this._path) {
2763
+ if (req.method === 'POST') {
2764
+ await this._handleMcpPost(req, res);
2765
+ return;
2766
+ }
2767
+ if (req.method === 'GET') {
2768
+ this._handleMcpGet(req, res);
2769
+ return;
2770
+ }
2771
+ res.writeHead(405, {
2772
+ 'Content-Type': 'application/json',
2773
+ Allow: 'GET, POST'
2774
+ });
2775
+ res.end(JSON.stringify({
2776
+ jsonrpc: '2.0',
2777
+ id: null,
2778
+ error: {
2779
+ code: -32601,
2780
+ message: 'Method not allowed'
2781
+ }
2782
+ }));
2783
+ return;
2784
+ }
2785
+ // 404 for unknown paths
2786
+ this._sendJsonRpcError(res, 404, -32601, 'Not Found');
2787
+ }
2788
+ /**
2789
+ * Send a JSON-RPC error response.
2790
+ */ _sendJsonRpcError(res, statusCode, code, message, id = null, extra) {
2791
+ const error = {
2792
+ code,
2793
+ message
2794
+ };
2795
+ if (extra) {
2796
+ Object.assign(error, extra);
2797
+ }
2798
+ res.writeHead(statusCode, {
2799
+ 'Content-Type': 'application/json'
2800
+ });
2801
+ res.end(JSON.stringify({
2802
+ jsonrpc: '2.0',
2803
+ id,
2804
+ error
2805
+ }));
2806
+ }
2807
+ /**
2808
+ * Handle POST /mcp — JSON-RPC method calls.
2809
+ *
2810
+ * Per the MCP Streamable HTTP spec:
2811
+ * - Accepts JSON-RPC request bodies
2812
+ * - Returns Mcp-Session-Id header for new sessions (stateful mode)
2813
+ * - Validates Mcp-Session-Id for existing sessions (stateful mode)
2814
+ * - Content-Type: application/json for responses
2815
+ */ async _handleMcpPost(req, res) {
2816
+ this._requestCount++;
2817
+ this._activeRequests++;
2818
+ const timeout = setTimeout(()=>{
2819
+ this._activeRequests--;
2820
+ this._sendJsonRpcError(res, 500, -32603, 'Request timeout');
2821
+ }, this._requestTimeout);
2822
+ try {
2823
+ // Read request body with size limit
2824
+ const body = await readRequestBody(req, this._bodySizeLimitEnabled ? this._maxBodySize : 0);
2825
+ if (body === null) {
2826
+ clearTimeout(timeout);
2827
+ this._activeRequests--;
2828
+ this._sendJsonRpcError(res, 413, -32000, 'Request body too large');
2829
+ return;
2830
+ }
2831
+ // Parse JSON
2832
+ let jsonRpcRequest;
2833
+ try {
2834
+ jsonRpcRequest = JSON.parse(body);
2835
+ } catch {
2836
+ clearTimeout(timeout);
2837
+ this._activeRequests--;
2838
+ this._sendJsonRpcError(res, 200, -32700, 'Parse error');
2839
+ return;
2840
+ }
2841
+ // Validate JSON-RPC schema
2842
+ const parseResult = (0,external_valibot_.safeParse)(schema/* .JsonRpcRequestSchema */.Uv, jsonRpcRequest);
2843
+ if (!parseResult.success) {
2844
+ clearTimeout(timeout);
2845
+ this._activeRequests--;
2846
+ this._sendJsonRpcError(res, 200, -32600, 'Invalid Request', jsonRpcRequest?.id ?? null, {
2847
+ data: parseResult.issues
2848
+ });
2849
+ return;
2850
+ }
2851
+ // Session management (stateful mode)
2852
+ let sessionId;
2853
+ if (this._stateful) {
2854
+ const sessionResult = this._resolveSession(req, res);
2855
+ if (sessionResult === false) {
2856
+ clearTimeout(timeout);
2857
+ this._activeRequests--;
2858
+ return;
2859
+ }
2860
+ sessionId = sessionResult;
2861
+ }
2862
+ // Check if MCP server is ready
2863
+ if (!this._mcpServer) {
2864
+ clearTimeout(timeout);
2865
+ this._activeRequests--;
2866
+ this._sendJsonRpcError(res, 503, -32603, 'Server not ready', jsonRpcRequest?.id ?? null);
2867
+ return;
2868
+ }
2869
+ // Process JSON-RPC request through MCP server
2870
+ // Process JSON-RPC request through MCP server with owner context
2871
+ const owner = this._stateful ? sessionId ?? (0,external_node_crypto_.randomUUID)() : (0,external_node_crypto_.randomUUID)();
2872
+ const response = await (0,RequestContext/* .runWithContext */.Vo)({
2873
+ requestId: (0,external_node_crypto_.randomUUID)(),
2874
+ owner
2875
+ }, ()=>this._mcpServer.receive(jsonRpcRequest, {
2876
+ sessionInfo: {}
2877
+ }));
2878
+ clearTimeout(timeout);
2879
+ this._activeRequests--;
2880
+ // Send response with session header if applicable
2881
+ const responseHeaders = {
2882
+ 'Content-Type': 'application/json'
2883
+ };
2884
+ if (sessionId) responseHeaders['Mcp-Session-Id'] = sessionId;
2885
+ if (response) {
2886
+ res.writeHead(200, responseHeaders);
2887
+ res.end(JSON.stringify(response));
2888
+ } else {
2889
+ if (sessionId) res.setHeader('Mcp-Session-Id', sessionId);
2890
+ res.writeHead(202);
2891
+ res.end();
2892
+ }
2893
+ } catch (error) {
2894
+ clearTimeout(timeout);
2895
+ this._activeRequests--;
2896
+ this._sendJsonRpcError(res, 200, -32603, 'Internal error', null, {
2897
+ data: (0,errors/* .getErrorMessage */.u1)(error)
2898
+ });
2899
+ }
2900
+ }
2901
+ /**
2902
+ * Handle GET /mcp — Optional SSE notification stream.
2903
+ *
2904
+ * Per the MCP Streamable HTTP spec, clients may open a GET request
2905
+ * to receive server-initiated notifications as SSE events.
2906
+ * Requires a valid Mcp-Session-Id in stateful mode.
2907
+ */ _handleMcpGet(req, res) {
2908
+ if (!this._stateful) {
2909
+ // SSE notification streams require stateful mode
2910
+ res.writeHead(405, {
2911
+ 'Content-Type': 'application/json',
2912
+ Allow: 'POST'
2913
+ });
2914
+ res.end(JSON.stringify({
2915
+ jsonrpc: '2.0',
2916
+ id: null,
2917
+ error: {
2918
+ code: -32601,
2919
+ message: 'GET not supported in stateless mode'
2920
+ }
2921
+ }));
2922
+ return;
2923
+ }
2924
+ // Require Mcp-Session-Id for GET requests
2925
+ const sessionId = this._getSessionIdFromHeader(req);
2926
+ if (!sessionId) {
2927
+ res.writeHead(400, {
2928
+ 'Content-Type': 'application/json'
2929
+ });
2930
+ res.end(JSON.stringify({
2931
+ jsonrpc: '2.0',
2932
+ id: null,
2933
+ error: {
2934
+ code: -32600,
2935
+ message: 'Missing Mcp-Session-Id header'
2936
+ }
2937
+ }));
2938
+ return;
2939
+ }
2940
+ const session = this._sessions.get(sessionId);
2941
+ if (!session) {
2942
+ res.writeHead(404, {
2943
+ 'Content-Type': 'application/json'
2944
+ });
2945
+ res.end(JSON.stringify({
2946
+ jsonrpc: '2.0',
2947
+ id: null,
2948
+ error: {
2949
+ code: -32001,
2950
+ message: 'Session not found'
2951
+ }
2952
+ }));
2953
+ return;
2954
+ }
2955
+ // Set SSE headers
2956
+ res.writeHead(200, {
2957
+ 'Content-Type': 'text/event-stream',
2958
+ 'Cache-Control': 'no-cache',
2959
+ Connection: 'keep-alive',
2960
+ 'Mcp-Session-Id': sessionId
2961
+ });
2962
+ // Send initial connected event
2963
+ this._sendSseEvent(res, 'connected', {
2964
+ sessionId,
2965
+ timestamp: Date.now()
2966
+ });
2967
+ // Track this notification stream
2968
+ session.notificationStreams.add(res);
2969
+ session.lastActivityAt = Date.now();
2970
+ this._updateSessionMetrics();
2971
+ // Handle client disconnect
2972
+ req.on('close', ()=>{
2973
+ session.notificationStreams.delete(res);
2974
+ this._updateSessionMetrics();
2975
+ });
2976
+ }
2977
+ /**
2978
+ * Resolve or create a session for a stateful request.
2979
+ *
2980
+ * @returns Session ID string on success, or `false` if the response was already sent (error).
2981
+ */ _resolveSession(req, res) {
2982
+ const headerSessionId = this._getSessionIdFromHeader(req);
2983
+ if (headerSessionId) {
2984
+ // Validate format
2985
+ if (!this.validateSessionId(headerSessionId)) {
2986
+ res.writeHead(400, {
2987
+ 'Content-Type': 'application/json'
2988
+ });
2989
+ res.end(JSON.stringify({
2990
+ jsonrpc: '2.0',
2991
+ id: null,
2992
+ error: {
2993
+ code: -32600,
2994
+ message: 'Invalid Mcp-Session-Id format'
2995
+ }
2996
+ }));
2997
+ return false;
2998
+ }
2999
+ // Check if session exists
3000
+ const session = this._sessions.get(headerSessionId);
3001
+ if (session) {
3002
+ session.lastActivityAt = Date.now();
3003
+ return headerSessionId;
3004
+ }
3005
+ // Unknown session ID — per spec, return 404
3006
+ res.writeHead(404, {
3007
+ 'Content-Type': 'application/json'
3008
+ });
3009
+ res.end(JSON.stringify({
3010
+ jsonrpc: '2.0',
3011
+ id: null,
3012
+ error: {
3013
+ code: -32001,
3014
+ message: 'Session not found'
3015
+ }
3016
+ }));
3017
+ return false;
3018
+ }
3019
+ // No session header — create new session
3020
+ const newSessionId = this._sessionIdGenerator();
3021
+ const sessionState = {
3022
+ id: newSessionId,
3023
+ createdAt: Date.now(),
3024
+ lastActivityAt: Date.now(),
3025
+ notificationStreams: new Set()
3026
+ };
3027
+ this._sessions.set(newSessionId, sessionState);
3028
+ this.log('info', `New session created: ${newSessionId}`);
3029
+ this._updateSessionMetrics();
3030
+ return newSessionId;
3031
+ }
3032
+ /**
3033
+ * Extract Mcp-Session-Id from request headers.
3034
+ */ _getSessionIdFromHeader(req) {
3035
+ const value = req.headers['mcp-session-id'];
3036
+ if (typeof value === 'string' && value.length > 0) {
3037
+ return value;
3038
+ }
3039
+ return undefined;
3040
+ }
3041
+ /**
3042
+ * Send an SSE event to a specific client response stream.
3043
+ */ _sendSseEvent(res, event, data) {
3044
+ try {
3045
+ res.write(`event: ${event}\n`);
3046
+ res.write(`data: ${JSON.stringify(data)}\n\n`);
3047
+ } catch {
3048
+ // Client disconnected — ignore
3049
+ }
3050
+ }
3051
+ /**
3052
+ * Broadcast a notification to all SSE streams in a given session.
3053
+ *
3054
+ * @param sessionId - Target session ID
3055
+ * @param event - SSE event name
3056
+ * @param data - Event payload
3057
+ */ broadcastToSession(sessionId, event, data) {
3058
+ const session = this._sessions.get(sessionId);
3059
+ if (!session) {
3060
+ return;
3061
+ }
3062
+ for (const stream of session.notificationStreams){
3063
+ this._sendSseEvent(stream, event, data);
3064
+ }
3065
+ }
3066
+ /**
3067
+ * Handle GET /metrics endpoint.
3068
+ */ _handleMetrics(res) {
3069
+ if (!this._metricsProvider) {
3070
+ res.writeHead(404, {
3071
+ 'Content-Type': 'text/plain'
3072
+ });
3073
+ res.end('Not Found');
3074
+ return;
3075
+ }
3076
+ res.writeHead(200, {
3077
+ 'Content-Type': 'text/plain; version=0.0.4; charset=utf-8'
3078
+ });
3079
+ res.end(this._metricsProvider());
3080
+ }
3081
+ /**
3082
+ * Handle GET /health — Liveness check.
3083
+ */ _handleHealthCheck(res) {
3084
+ const healthData = {
3085
+ status: 'healthy',
3086
+ requests: this._requestCount,
3087
+ sessions: this._sessions.size,
3088
+ transport: 'streamable-http'
3089
+ };
3090
+ if (this._healthChecker) {
3091
+ const liveness = this._healthChecker.checkLiveness();
3092
+ healthData.liveness = liveness;
3093
+ }
3094
+ res.writeHead(200, {
3095
+ 'Content-Type': 'application/json'
3096
+ });
3097
+ res.end(JSON.stringify(healthData));
3098
+ }
3099
+ /**
3100
+ * Handle GET /ready — Readiness check.
3101
+ */ async _handleReadinessCheck(res) {
3102
+ if (this._healthChecker) {
3103
+ const readiness = await this._healthChecker.checkReadiness();
3104
+ const statusCode = readiness.status === 'ok' ? 200 : 503;
3105
+ res.writeHead(statusCode, {
3106
+ 'Content-Type': 'application/json'
3107
+ });
3108
+ res.end(JSON.stringify(readiness));
3109
+ } else {
3110
+ res.writeHead(200, {
3111
+ 'Content-Type': 'application/json'
3112
+ });
3113
+ res.end(JSON.stringify({
3114
+ status: 'ok',
3115
+ timestamp: new Date().toISOString(),
3116
+ components: {}
3117
+ }));
3118
+ }
3119
+ }
3120
+ /**
3121
+ * Update session-related metrics.
3122
+ */ _updateSessionMetrics() {
3123
+ this._metrics?.gauge('streamable_http_active_sessions', this._sessions.size, {}, 'Active Streamable HTTP sessions');
3124
+ let totalStreams = 0;
3125
+ for (const session of this._sessions.values()){
3126
+ totalStreams += session.notificationStreams.size;
3127
+ }
3128
+ this._metrics?.gauge('streamable_http_notification_streams', totalStreams, {}, 'Active SSE notification streams');
3129
+ }
3130
+ /**
3131
+ * Stop transport server with graceful shutdown.
3132
+ *
3133
+ * @param timeout - Maximum time to wait for in-flight requests (default: 30s)
3134
+ */ async stop(timeout) {
3135
+ this._isShuttingDown = true;
3136
+ this._stopRateLimitCleanup();
3137
+ const shutdownTimeout = timeout ?? 30000;
3138
+ // Close all SSE notification streams
3139
+ for (const session of this._sessions.values()){
3140
+ for (const stream of session.notificationStreams){
3141
+ try {
3142
+ stream.end();
3143
+ } catch {
3144
+ // Ignore errors
3145
+ }
3146
+ }
3147
+ session.notificationStreams.clear();
3148
+ }
3149
+ this._sessions.clear();
3150
+ return new Promise((resolve)=>{
3151
+ if (!this._server) {
3152
+ this.log('info', 'Streamable HTTP transport stopped (no server)');
3153
+ resolve();
3154
+ return;
3155
+ }
3156
+ // Force close after timeout
3157
+ const forceClose = setTimeout(()=>{
3158
+ this.log('warn', 'Streamable HTTP transport force-closing after timeout');
3159
+ resolve();
3160
+ }, shutdownTimeout);
3161
+ this._server.close(()=>{
3162
+ clearTimeout(forceClose);
3163
+ this.log('info', 'Streamable HTTP transport stopped');
3164
+ resolve();
3165
+ });
3166
+ });
3167
+ }
3168
+ }
3169
+ /**
3170
+ * Create a Streamable HTTP transport with given options.
3171
+ *
3172
+ * @param options - Transport configuration
3173
+ * @returns A configured Streamable HTTP transport
3174
+ *
3175
+ * @example
3176
+ * ```typescript
3177
+ * const transport = createStreamableHttpTransport({ port: 3000, stateful: true });
3178
+ * await transport.connect(server);
3179
+ * ```
3180
+ */ function createStreamableHttpTransport(options = {}) {
3181
+ return new StreamableHttpTransport(options);
3182
+ }
3183
+
3184
+
3185
+ },
3186
+ 65(module) {
3187
+
3188
+ module.exports = __rspack_external__lib_js_262c9725;
3189
+
3190
+
3191
+ },
3192
+ 561(module) {
3193
+
3194
+ module.exports = __rspack_external_node_crypto_9ba42079;
3195
+
3196
+
3197
+ },
3198
+ 316(module) {
3199
+
3200
+ module.exports = __rspack_external_node_http_2dc67212;
3201
+
3202
+
3203
+ },
3204
+ 61(module) {
3205
+
3206
+ module.exports = __rspack_external_node_url_e96de089;
3207
+
3208
+
3209
+ },
3210
+ 821(module) {
3211
+
3212
+ module.exports = __rspack_external_valibot;
3213
+
3214
+
3215
+ },
3216
+
3217
+ });
3218
+ // The module cache
3219
+ var __webpack_module_cache__ = {};
3220
+
3221
+ // The require function
3222
+ function __webpack_require__(moduleId) {
3223
+
3224
+ // Check if module is in cache
3225
+ var cachedModule = __webpack_module_cache__[moduleId];
3226
+ if (cachedModule !== undefined) {
3227
+ return cachedModule.exports;
3228
+ }
3229
+ // Create a new module (and put it into the cache)
3230
+ var module = (__webpack_module_cache__[moduleId] = {
3231
+ exports: {}
3232
+ });
3233
+ // Execute the module function
3234
+ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
3235
+
3236
+ // Return the exports of the module
3237
+ return module.exports;
3238
+
3239
+ }
3240
+
3241
+ // webpack/runtime/define_property_getters
3242
+ (() => {
3243
+ __webpack_require__.d = (exports, definition) => {
3244
+ for(var key in definition) {
3245
+ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
3246
+ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
3247
+ }
3248
+ }
3249
+ };
3250
+ })();
3251
+ // webpack/runtime/has_own_property
3252
+ (() => {
3253
+ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
3254
+ })();
3255
+ var __webpack_exports__ = {};
3256
+ // This entry needs to be wrapped in an IIFE because it needs to be isolated against other modules in the chunk.
3257
+ (() => {
3258
+
3259
+ ;// CONCATENATED MODULE: external "@tmcp/adapter-valibot"
3260
+
3261
+ ;// CONCATENATED MODULE: external "@tmcp/transport-stdio"
3262
+
3263
+ ;// CONCATENATED MODULE: external "node:fs"
3264
+
3265
+ ;// CONCATENATED MODULE: external "node:path"
3266
+
3267
+ // EXTERNAL MODULE: external "node:url"
3268
+ var external_node_url_ = __webpack_require__(61);
3269
+ ;// CONCATENATED MODULE: external "tmcp"
3270
+
3271
+ // EXTERNAL MODULE: external "./lib.js"
3272
+ var external_lib_js_ = __webpack_require__(65);
3273
+ // EXTERNAL MODULE: ./src/context/RequestContext.ts + 1 modules
3274
+ var RequestContext = __webpack_require__(923);
3275
+ ;// CONCATENATED MODULE: ./src/logger/StructuredLogger.ts
3276
+ /**
3277
+ * Lightweight structured logging without external dependencies.
3278
+ *
3279
+ * This module provides a structured logging implementation that writes to stderr
3280
+ * for MCP server compatibility. It supports multiple log levels, pretty printing,
3281
+ * and hierarchical child loggers with inherited context.
3282
+ *
3283
+ * @module logger
3284
+ */
3285
+ /**
3286
+ * Structured logger with level filtering and context support.
3287
+ *
3288
+ * This logger provides structured logging capabilities with configurable
3289
+ * output formats, log levels, and hierarchical context. All output is
3290
+ * written to stderr for compatibility with MCP servers.
3291
+ *
3292
+ * @remarks
3293
+ * **Log Level Priority** (lowest to highest):
3294
+ * - `debug` (0) - Detailed debugging information
3295
+ * - `info` (1) - General informational messages
3296
+ * - `warn` (2) - Warning messages for potential issues
3297
+ * - `error` (3) - Error messages for failures
3298
+ *
3299
+ * Only messages at or above the configured level will be output.
3300
+ *
3301
+ * **Output Formats:**
3302
+ * - Pretty (default): `[timestamp] [LEVEL] [context] message {meta}`
3303
+ * - JSON: `{"level":"info","message":"...","timestamp":"...","context":"...","meta":{...}}`
3304
+ *
3305
+ * @example
3306
+ * ```typescript
3307
+ * // Create a logger
3308
+ * const logger = new StructuredLogger({
3309
+ * level: 'info',
3310
+ * context: 'SequentialThinking',
3311
+ * pretty: true
3312
+ * });
3313
+ *
3314
+ * // Log messages
3315
+ * logger.debug('Detailed debug info', { userId: '123' });
3316
+ * logger.info('Server started', { port: 3000 });
3317
+ * logger.warn('High memory usage', { usage: '85%' });
3318
+ * logger.error('Connection failed', { error: 'ECONNREFUSED' });
3319
+ *
3320
+ * // Create a child logger with extended context
3321
+ * const childLogger = logger.createChild('Database');
3322
+ * childLogger.info('Query executed', { rows: 42 });
3323
+ * // Output: [timestamp] [INFO] [SequentialThinking:Database] Query executed {"rows":42}
3324
+ * ```
3325
+ */ class StructuredLogger {
3326
+ /** Current minimum log level. */ _level;
3327
+ /** Default context for log messages. */ _context;
3328
+ /** Whether pretty printing is enabled. */ _pretty;
3329
+ /**
3330
+ * Log level priority ordering for filtering.
3331
+ * Higher numbers = higher severity.
3332
+ * @private
3333
+ */ static LEVEL_PRIORITY = {
3334
+ debug: 0,
3335
+ info: 1,
3336
+ warn: 2,
3337
+ error: 3
3338
+ };
3339
+ /**
3340
+ * Creates a new StructuredLogger instance.
3341
+ *
3342
+ * @param options - Configuration options for the logger
3343
+ *
3344
+ * @example
3345
+ * ```typescript
3346
+ * // Default configuration
3347
+ * const logger1 = new StructuredLogger();
3348
+ *
3349
+ * // Custom configuration
3350
+ * const logger2 = new StructuredLogger({
3351
+ * level: 'debug',
3352
+ * context: 'MyApp',
3353
+ * pretty: false // JSON output
3354
+ * });
3355
+ * ```
3356
+ */ constructor(options = {}){
3357
+ this._level = options.level ?? 'info';
3358
+ this._context = options.context ?? 'SequentialThinking';
3359
+ this._pretty = options.pretty ?? true;
3360
+ }
3361
+ /**
3362
+ * Determines whether a message at the given level should be logged.
3363
+ * @param level - The log level to check
3364
+ * @returns true if the level meets the threshold, false otherwise
3365
+ * @private
3366
+ */ shouldLog(level) {
3367
+ return StructuredLogger.LEVEL_PRIORITY[level] >= StructuredLogger.LEVEL_PRIORITY[this._level];
3368
+ }
3369
+ /**
3370
+ * Formats a log entry for output.
3371
+ * @param entry - The log entry to format
3372
+ * @returns Formatted string representation
3373
+ * @private
3374
+ */ format(entry) {
3375
+ if (this._pretty) {
3376
+ const metaStr = entry.meta ? ` ${JSON.stringify(entry.meta)}` : '';
3377
+ const requestIdStr = entry.requestId ? ` [${entry.requestId}]` : '';
3378
+ return `[${entry.timestamp}] [${entry.level.toUpperCase()}]${entry.context ? ` [${entry.context}]` : ''}${requestIdStr} ${entry.message}${metaStr}`;
3379
+ }
3380
+ return JSON.stringify(entry);
3381
+ }
3382
+ /**
3383
+ * Internal logging method that handles level filtering and output.
3384
+ * @param level - The log level for this message
3385
+ * @param message - The message to log
3386
+ * @param meta - Optional structured metadata
3387
+ * @private
3388
+ */ log(level, message, meta) {
3389
+ if (!this.shouldLog(level)) return;
3390
+ const requestId = (0,RequestContext/* .getRequestId */.RE)();
3391
+ const entry = {
3392
+ level,
3393
+ message,
3394
+ timestamp: new Date().toISOString(),
3395
+ context: this._context,
3396
+ meta,
3397
+ ...requestId ? {
3398
+ requestId
3399
+ } : {}
3400
+ };
3401
+ const formatted = this.format(entry);
3402
+ // Write to stderr for MCP server compatibility
3403
+ console.error(formatted);
3404
+ }
3405
+ /**
3406
+ * Log a debug message.
3407
+ *
3408
+ * Debug messages contain detailed information typically used for
3409
+ * troubleshooting and development. Only output when log level is 'debug'.
3410
+ *
3411
+ * @param message - The message to log
3412
+ * @param meta - Optional structured metadata
3413
+ *
3414
+ * @example
3415
+ * ```typescript
3416
+ * logger.debug('Processing request', { path: '/api/users', method: 'GET' });
3417
+ * ```
3418
+ */ debug(message, meta) {
3419
+ this.log('debug', message, meta);
3420
+ }
3421
+ /**
3422
+ * Log an info message.
3423
+ *
3424
+ * Info messages contain general informational messages about normal operation.
3425
+ * Output when log level is 'info' or lower.
3426
+ *
3427
+ * @param message - The message to log
3428
+ * @param meta - Optional structured metadata
3429
+ *
3430
+ * @example
3431
+ * ```typescript
3432
+ * logger.info('Server started', { port: 3000, env: 'production' });
3433
+ * ```
3434
+ */ info(message, meta) {
3435
+ this.log('info', message, meta);
3436
+ }
3437
+ /**
3438
+ * Log a warning message.
3439
+ *
3440
+ * Warning messages indicate potential issues that don't prevent operation
3441
+ * but may require attention. Output when log level is 'warn' or lower.
3442
+ *
3443
+ * @param message - The message to log
3444
+ * @param meta - Optional structured metadata
3445
+ *
3446
+ * @example
3447
+ * ```typescript
3448
+ * logger.warn('High memory usage detected', { usage: '85%', threshold: '80%' });
3449
+ * ```
3450
+ */ warn(message, meta) {
3451
+ this.log('warn', message, meta);
3452
+ }
3453
+ /**
3454
+ * Log an error message.
3455
+ *
3456
+ * Error messages indicate failures or error conditions. Always output
3457
+ * regardless of log level setting.
3458
+ *
3459
+ * @param message - The message to log
3460
+ * @param meta - Optional structured metadata
3461
+ *
3462
+ * @example
3463
+ * ```typescript
3464
+ * logger.error('Database connection failed', { error: err.message, code: err.code });
3465
+ * ```
3466
+ */ error(message, meta) {
3467
+ this.log('error', message, meta);
3468
+ }
3469
+ /**
3470
+ * Creates a child logger with inherited settings and extended context.
3471
+ *
3472
+ * Child loggers inherit the parent's log level and pretty print setting,
3473
+ * but have their context appended to the parent's context for hierarchical logging.
3474
+ *
3475
+ * @param context - Additional context to append to the parent's context
3476
+ * @returns A new logger instance with extended context
3477
+ *
3478
+ * @example
3479
+ * ```typescript
3480
+ * const parentLogger = new StructuredLogger({ context: 'App' });
3481
+ * const dbLogger = parentLogger.createChild('Database');
3482
+ * const queryLogger = dbLogger.createChild('Query');
3483
+ *
3484
+ * parentLogger.info('Starting up');
3485
+ * // Output: [timestamp] [INFO] [App] Starting up
3486
+ *
3487
+ * dbLogger.info('Connected');
3488
+ * // Output: [timestamp] [INFO] [App:Database] Connected
3489
+ *
3490
+ * queryLogger.info('Executed in 5ms');
3491
+ * // Output: [timestamp] [INFO] [App:Database:Query] Executed in 5ms
3492
+ * ```
3493
+ */ createChild(context) {
3494
+ return new StructuredLogger({
3495
+ level: this._level,
3496
+ context: `${this._context}:${context}`,
3497
+ pretty: this._pretty
3498
+ });
3499
+ }
3500
+ /**
3501
+ * Sets the minimum log level.
3502
+ *
3503
+ * Only messages at or above this level will be output.
3504
+ *
3505
+ * @param level - The new minimum log level
3506
+ *
3507
+ * @example
3508
+ * ```typescript
3509
+ * logger.setLevel('debug'); // Enable all logging
3510
+ * logger.setLevel('error'); // Only show errors
3511
+ * ```
3512
+ */ setLevel(level) {
3513
+ this._level = level;
3514
+ }
3515
+ /**
3516
+ * Gets the current minimum log level.
3517
+ *
3518
+ * @returns The current log level
3519
+ *
3520
+ * @example
3521
+ * ```typescript
3522
+ * const currentLevel = logger.getLevel();
3523
+ * console.log(`Current level: ${currentLevel}`);
3524
+ * ```
3525
+ */ getLevel() {
3526
+ return this._level;
3527
+ }
3528
+ }
3529
+
3530
+ // EXTERNAL MODULE: ./src/errors.ts
3531
+ var errors = __webpack_require__(937);
3532
+ // EXTERNAL MODULE: ./src/schema.ts
3533
+ var schema = __webpack_require__(613);
3534
+ ;// CONCATENATED MODULE: ./src/cli.ts
3535
+ //#!/usr/bin/env bun
3536
+ // CLI entry point for tracelattice MCP server.
3537
+ // This file handles CLI argument parsing, transport selection, and signal handlers.
3538
+ // For library usage, import from './lib.js' or './index.js' instead.
3539
+
3540
+
3541
+
3542
+
3543
+
3544
+
3545
+
3546
+
3547
+
107
3548
 
108
- `),t.end();return}this._clientSessionMap.set(t,i),this._updatePoolMetrics()}let n={timestamp:Date.now()};i&&(n.sessionId=i),this._sendSseEvent(t,"connected",n),this._clients.add(t),this._updateActiveConnectionsMetric(),e.on("close",()=>{this._clients.delete(t),this._clientSessionMap.delete(t),this._updateActiveConnectionsMetric()});let o=this._generateClientId(),r=this._messageQueue.get(o);if(r){for(let e of r)this._sendSseEvent(t,"message",e);this._messageQueue.delete(o)}}async _handleMessage(e,t,s){var i,n,a;let l="";for await(let t of e)l+=t.toString();try{let e=JSON.parse(l),s=(0,o.safeParse)(r.Uv,e);if(!s.success){null==(i=this._metrics)||i.counter("http_request_errors_total",1,{transport:"sse",error_type:"validation"},"Total HTTP request errors"),t.writeHead(200,{"Content-Type":"application/json"}),t.end(JSON.stringify({jsonrpc:"2.0",id:(null==e?void 0:e.id)??null,error:{code:-32600,message:"Invalid Request",data:s.issues}}));return}if(this._mcpServer){let s=await this._mcpServer.receive(e,{sessionInfo:{}});t.writeHead(200,{"Content-Type":"application/json"}),s?t.end(JSON.stringify(s)):t.end(JSON.stringify({jsonrpc:"2.0",id:(null==e?void 0:e.id)??null,result:null}))}else null==(n=this._metrics)||n.counter("http_request_errors_total",1,{transport:"sse",error_type:"server_not_ready"},"Total HTTP request errors"),t.writeHead(503,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Server not ready"}))}catch{null==(a=this._metrics)||a.counter("http_request_errors_total",1,{transport:"sse",error_type:"parse_error"},"Total HTTP request errors"),t.writeHead(400,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Invalid JSON"}))}}_sendSseEvent(e,t,s){try{e.write(`event: ${t}
109
- `),e.write(`data: ${JSON.stringify(s)}
3549
+ // Get version from package.json
3550
+ const cli_filename = (0,external_node_url_.fileURLToPath)(import.meta.url);
3551
+ const cli_dirname = (0,__rspack_external_node_path_c5b9b54f.dirname)(cli_filename);
3552
+ const package_json = JSON.parse((0,__rspack_external_node_fs_5ea92f0c.readFileSync)((0,__rspack_external_node_path_c5b9b54f.join)(cli_dirname, '../package.json'), 'utf-8'));
3553
+ const { name: cli_name, version } = package_json;
3554
+ // Handle CLI arguments
3555
+ const args = process.argv.slice(2);
3556
+ const shouldShowVersion = args.includes('--version') || args.includes('-v');
3557
+ if (shouldShowVersion) {
3558
+ console.log(`${cli_name} v${version}`);
3559
+ process.exit(0);
3560
+ }
3561
+ async function main() {
3562
+ const adapter = new __rspack_external__tmcp_adapter_valibot_fbccc1df.ValibotJsonSchemaAdapter();
3563
+ const server = new __rspack_external_tmcp.McpServer({
3564
+ name: cli_name,
3565
+ version,
3566
+ description: 'Semantic Sequential Thinking MCP Server'
3567
+ }, {
3568
+ adapter,
3569
+ capabilities: {
3570
+ tools: {
3571
+ listChanged: true
3572
+ }
3573
+ }
3574
+ });
3575
+ const thinkingServer = await (0,external_lib_js_.initializeServer)();
3576
+ server.tool({
3577
+ name: 'sequentialthinking_tools',
3578
+ description: schema/* .SEQUENTIAL_THINKING_TOOL.description */.iV.description,
3579
+ schema: schema/* .SequentialThinkingSchema */.ZK
3580
+ }, async (input)=>{
3581
+ return thinkingServer.processThought(input);
3582
+ });
3583
+ const transportType = process.env.TRANSPORT_TYPE || 'stdio';
3584
+ if (transportType === 'sse') {
3585
+ await startSseTransport(server, thinkingServer);
3586
+ } else if (transportType === 'streamable-http') {
3587
+ await startStreamableHttpTransport(server, thinkingServer);
3588
+ } else {
3589
+ await startStdioTransport(server, thinkingServer);
3590
+ }
3591
+ }
3592
+ /**
3593
+ * Start SSE transport for multi-user support
3594
+ */ async function startSseTransport(server, thinkingServer) {
3595
+ const { SseTransport } = await Promise.resolve(/* import() */).then(__webpack_require__.bind(__webpack_require__, 390));
3596
+ const { createConnectionPool } = await Promise.resolve(/* import() */).then(__webpack_require__.bind(__webpack_require__, 789));
3597
+ const port = parseInt(process.env.SSE_PORT || '3000', 10);
3598
+ const host = process.env.SSE_HOST || 'localhost';
3599
+ const transportMetrics = thinkingServer.getContainer().resolve('Metrics');
3600
+ const enablePool = process.env.SSE_ENABLE_POOL !== 'false';
3601
+ const maxSessions = parseInt(process.env.SSE_MAX_SESSIONS || '100', 10);
3602
+ const sessionTimeout = parseInt(process.env.SSE_SESSION_TIMEOUT || '300000', 10);
3603
+ const connectionPool = enablePool ? createConnectionPool({
3604
+ maxSessions,
3605
+ sessionTimeout,
3606
+ logger: thinkingServer['_logger'],
3607
+ serverFactory: async ()=>{
3608
+ const { createServer: createThinkingServer } = await Promise.resolve(/* import() */).then(__webpack_require__.bind(__webpack_require__, 65));
3609
+ const sessionServer = await createThinkingServer({
3610
+ autoDiscover: true
3611
+ });
3612
+ return sessionServer;
3613
+ }
3614
+ }) : undefined;
3615
+ const sseTransport = new SseTransport({
3616
+ port,
3617
+ host,
3618
+ corsOrigin: process.env.CORS_ORIGIN || '*',
3619
+ enableCors: process.env.ENABLE_CORS !== 'false',
3620
+ allowedHosts: process.env.ALLOWED_HOSTS?.split(',').map((hostValue)=>hostValue.trim()),
3621
+ metrics: transportMetrics,
3622
+ connectionPool
3623
+ });
3624
+ // Connect the SSE transport
3625
+ await sseTransport.connect(server);
3626
+ const shutdown = async ()=>{
3627
+ await sseTransport.stop();
3628
+ await thinkingServer.stop();
3629
+ };
3630
+ registerShutdownHandlers(shutdown);
3631
+ thinkingServer['_logger'].info(`Sequential Thinking MCP Server running on SSE transport at http://${host}:${port}`);
3632
+ }
3633
+ /**
3634
+ * Start Streamable HTTP transport (MCP spec recommended)
3635
+ */ async function startStreamableHttpTransport(server, thinkingServer) {
3636
+ const { StreamableHttpTransport } = await Promise.resolve(/* import() */).then(__webpack_require__.bind(__webpack_require__, 34));
3637
+ const port = parseInt(process.env.STREAMABLE_HTTP_PORT || process.env.SSE_PORT || '3000', 10);
3638
+ const host = process.env.STREAMABLE_HTTP_HOST || process.env.SSE_HOST || 'localhost';
3639
+ const transportMetrics = thinkingServer.getContainer().resolve('Metrics');
3640
+ const stateful = process.env.STREAMABLE_HTTP_STATEFUL !== 'false';
3641
+ const streamableTransport = new StreamableHttpTransport({
3642
+ port,
3643
+ host,
3644
+ corsOrigin: process.env.CORS_ORIGIN || '*',
3645
+ enableCors: process.env.ENABLE_CORS !== 'false',
3646
+ allowedHosts: process.env.ALLOWED_HOSTS?.split(',').map((hostValue)=>hostValue.trim()),
3647
+ metrics: transportMetrics,
3648
+ stateful
3649
+ });
3650
+ // Connect the Streamable HTTP transport
3651
+ await streamableTransport.connect(server);
3652
+ const shutdown = async ()=>{
3653
+ await streamableTransport.stop();
3654
+ await thinkingServer.stop();
3655
+ };
3656
+ registerShutdownHandlers(shutdown);
3657
+ thinkingServer['_logger'].info(`Sequential Thinking MCP Server running on Streamable HTTP transport at http://${host}:${port}`);
3658
+ }
3659
+ /**
3660
+ * Start stdio transport (default, single-user)
3661
+ */ async function startStdioTransport(server, thinkingServer) {
3662
+ const transport = new __rspack_external__tmcp_transport_stdio_9731848f.StdioTransport(server);
3663
+ transport.listen();
3664
+ const shutdown = async ()=>{
3665
+ const forceExit = setTimeout(()=>{
3666
+ thinkingServer['_logger'].error('Graceful shutdown timed out after 30s - forcing exit');
3667
+ process.exit(1);
3668
+ }, 30000).unref(); // 30s timeout, don't keep process alive
3669
+ try {
3670
+ await thinkingServer.stop();
3671
+ clearTimeout(forceExit);
3672
+ process.exit(0);
3673
+ } catch (error) {
3674
+ thinkingServer['_logger'].error('Error during shutdown', {
3675
+ error: (0,errors/* .getErrorMessage */.u1)(error)
3676
+ });
3677
+ process.exit(1);
3678
+ }
3679
+ };
3680
+ // Register signal handlers ONCE (fixes double-registration bug)
3681
+ process.once('SIGINT', ()=>void shutdown());
3682
+ process.once('SIGTERM', ()=>void shutdown());
3683
+ thinkingServer['_logger'].info('Sequential Thinking MCP Server running on stdio');
3684
+ }
3685
+ /**
3686
+ * Register shutdown signal handlers for a common pattern
3687
+ */ function registerShutdownHandlers(shutdown) {
3688
+ process.once('SIGINT', ()=>{
3689
+ shutdown().then(()=>process.exit(0)).catch(()=>process.exit(1));
3690
+ });
3691
+ process.once('SIGTERM', ()=>{
3692
+ shutdown().then(()=>process.exit(0)).catch(()=>process.exit(1));
3693
+ });
3694
+ }
3695
+ main().catch((error)=>{
3696
+ const logger = new StructuredLogger({
3697
+ level: 'error',
3698
+ context: 'SequentialThinking',
3699
+ pretty: true
3700
+ });
3701
+ logger.error('Fatal error running server', {
3702
+ error: (0,errors/* .getErrorMessage */.u1)(error)
3703
+ });
3704
+ process.exit(1);
3705
+ });
110
3706
 
111
- `)}catch{this._clients.delete(e),this._updateActiveConnectionsMetric()}}_updateActiveConnectionsMetric(){var e;null==(e=this._metrics)||e.gauge("sse_active_connections",this._clients.size,{},"Current active SSE connections")}_updatePoolMetrics(){if(!this._connectionPool||!this._metrics)return;let e=this._connectionPool.getStats();this._metrics.gauge("sse_pool_active_sessions",e.activeSessions,{},"Active sessions in connection pool"),this._metrics.gauge("sse_pool_total_sessions",e.totalSessions,{},"Total sessions in connection pool"),this._metrics.gauge("sse_pool_max_sessions",e.maxSessions,{},"Maximum sessions in connection pool")}broadcast(e,t){for(let s of this._clients)this._sendSseEvent(s,e,t)}_generateClientId(){return`client_${Date.now()}_${Math.random().toString(36).substring(2,11)}`}get clientCount(){return this._clients.size}get connectionPool(){return this._connectionPool}async stop(e){return this._isShuttingDown=!0,this._stopRateLimitCleanup(),this._connectionPool&&await this._connectionPool.terminate(),new Promise(e=>{for(let e of this._clients)try{e.end()}catch{}this._clients.clear(),this._clientSessionMap.clear(),this._updateActiveConnectionsMetric(),this._server.close(()=>{this.log("info","SSE transport stopped"),e()})})}}},756(e,t,s){s.d(t,{StreamableHttpTransport:()=>h});var i=s(561),n=s(316),o=s(821),r=s(787),a=s(555),l=s(681);async function c(e,t){let s="",i=0;for await(let n of e){let e="string"==typeof n?n:n.toString();if(i+=e.length,t>0&&i>t)return null;s+=e}return s}class h extends l.j{_server=null;_mcpServer=null;_path;_stateful;_sessionIdGenerator;_sessions=new Map;_requestCount=0;_activeRequests=0;_bodySizeLimitEnabled;_maxBodySize;_requestTimeout;_metrics;_metricsProvider;constructor(e={}){super(e),this._path=e.path??"/mcp",this._stateful=e.stateful??!0,this._sessionIdGenerator=e.sessionIdGenerator??(()=>(0,i.randomUUID)()),this._bodySizeLimitEnabled=e.enableBodySizeLimit??!0,this._maxBodySize=e.maxBodySize??0xa00000,this._requestTimeout=e.requestTimeout??3e4,this._metrics=e.metrics,this._metricsProvider=e.metricsProvider??null}get clientCount(){return this._stateful?this._sessions.size:this._activeRequests}get requestCount(){return this._requestCount}async connect(e){return this._mcpServer=e,this._server=(0,n.createServer)((e,t)=>this._handleRequest(e,t)),new Promise(e=>{this._server.listen(this._port,this._host,()=>{this.log("info",`Streamable HTTP transport listening on http://${this._host}:${this._port}`),e()})})}async _handleRequest(e,t){var s,i;let n=Date.now();if(null==(s=this._metrics)||s.counter("streamable_http_requests_total",1,{},"Total Streamable HTTP transport requests"),t.once("finish",()=>{var e;let t=(Date.now()-n)/1e3;null==(e=this._metrics)||e.histogram("streamable_http_request_duration_seconds",t,{})}),!this.validateHostHeader(e))return void this._sendJsonRpcError(t,403,-32e3,"Forbidden - invalid host header");if(this.isShuttingDown())return void this._sendJsonRpcError(t,503,-32603,"Server is shutting down");let o=this.getClientIp(e);if(this.checkRateLimit(o)){t.setHeader("Retry-After","60"),this._sendJsonRpcError(t,429,-32e3,"Too many requests");return}if(!this.validateCorsOrigin(e))return void this._sendJsonRpcError(t,403,-32e3,"Forbidden - invalid origin");if(this.setCorsHeaders(t),"OPTIONS"===e.method){t.setHeader("Access-Control-Allow-Headers","Content-Type, Mcp-Session-Id"),t.writeHead(204),t.end();return}let r=(null==(i=e.url)?void 0:i.split("?")[0])??"/";"GET"===e.method&&"/metrics"===r?this._handleMetrics(t):"GET"===e.method&&"/health"===r?this._handleHealthCheck(t):"GET"===e.method&&"/ready"===r?await this._handleReadinessCheck(t):r===this._path?"POST"===e.method?await this._handleMcpPost(e,t):"GET"===e.method?this._handleMcpGet(e,t):(t.writeHead(405,{"Content-Type":"application/json",Allow:"GET, POST"}),t.end(JSON.stringify({jsonrpc:"2.0",id:null,error:{code:-32601,message:"Method not allowed"}}))):this._sendJsonRpcError(t,404,-32601,"Not Found")}_sendJsonRpcError(e,t,s,i,n=null,o){let r={code:s,message:i};o&&Object.assign(r,o),e.writeHead(t,{"Content-Type":"application/json"}),e.end(JSON.stringify({jsonrpc:"2.0",id:n,error:r}))}async _handleMcpPost(e,t){this._requestCount++,this._activeRequests++;let s=setTimeout(()=>{this._activeRequests--,this._sendJsonRpcError(t,500,-32603,"Request timeout")},this._requestTimeout);try{let i,n,r=await c(e,this._bodySizeLimitEnabled?this._maxBodySize:0);if(null===r){clearTimeout(s),this._activeRequests--,this._sendJsonRpcError(t,413,-32e3,"Request body too large");return}try{i=JSON.parse(r)}catch{clearTimeout(s),this._activeRequests--,this._sendJsonRpcError(t,200,-32700,"Parse error");return}let l=(0,o.safeParse)(a.Uv,i);if(!l.success){clearTimeout(s),this._activeRequests--,this._sendJsonRpcError(t,200,-32600,"Invalid Request",(null==i?void 0:i.id)??null,{data:l.issues});return}if(this._stateful){let i=this._resolveSession(e,t);if(!1===i){clearTimeout(s),this._activeRequests--;return}n=i}if(!this._mcpServer){clearTimeout(s),this._activeRequests--,this._sendJsonRpcError(t,503,-32603,"Server not ready",(null==i?void 0:i.id)??null);return}let h=await this._mcpServer.receive(i,{sessionInfo:{}});clearTimeout(s),this._activeRequests--;let p={"Content-Type":"application/json"};n&&(p["Mcp-Session-Id"]=n),h?(t.writeHead(200,p),t.end(JSON.stringify(h))):(n&&t.setHeader("Mcp-Session-Id",n),t.writeHead(202),t.end())}catch(e){clearTimeout(s),this._activeRequests--,this._sendJsonRpcError(t,200,-32603,"Internal error",null,{data:(0,r.u1)(e)})}}_handleMcpGet(e,t){if(!this._stateful){t.writeHead(405,{"Content-Type":"application/json",Allow:"POST"}),t.end(JSON.stringify({jsonrpc:"2.0",id:null,error:{code:-32601,message:"GET not supported in stateless mode"}}));return}let s=this._getSessionIdFromHeader(e);if(!s){t.writeHead(400,{"Content-Type":"application/json"}),t.end(JSON.stringify({jsonrpc:"2.0",id:null,error:{code:-32600,message:"Missing Mcp-Session-Id header"}}));return}let i=this._sessions.get(s);if(!i){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({jsonrpc:"2.0",id:null,error:{code:-32001,message:"Session not found"}}));return}t.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive","Mcp-Session-Id":s}),this._sendSseEvent(t,"connected",{sessionId:s,timestamp:Date.now()}),i.notificationStreams.add(t),i.lastActivityAt=Date.now(),this._updateSessionMetrics(),e.on("close",()=>{i.notificationStreams.delete(t),this._updateSessionMetrics()})}_resolveSession(e,t){let s=this._getSessionIdFromHeader(e);if(s){if(!this.validateSessionId(s))return t.writeHead(400,{"Content-Type":"application/json"}),t.end(JSON.stringify({jsonrpc:"2.0",id:null,error:{code:-32600,message:"Invalid Mcp-Session-Id format"}})),!1;let e=this._sessions.get(s);return e?(e.lastActivityAt=Date.now(),s):(t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({jsonrpc:"2.0",id:null,error:{code:-32001,message:"Session not found"}})),!1)}let i=this._sessionIdGenerator(),n={id:i,createdAt:Date.now(),lastActivityAt:Date.now(),notificationStreams:new Set};return this._sessions.set(i,n),this.log("info",`New session created: ${i}`),this._updateSessionMetrics(),i}_getSessionIdFromHeader(e){let t=e.headers["mcp-session-id"];if("string"==typeof t&&t.length>0)return t}_sendSseEvent(e,t,s){try{e.write(`event: ${t}
112
- `),e.write(`data: ${JSON.stringify(s)}
3707
+ })();
113
3708
 
114
- `)}catch{}}broadcastToSession(e,t,s){let i=this._sessions.get(e);if(i)for(let e of i.notificationStreams)this._sendSseEvent(e,t,s)}_handleMetrics(e){if(!this._metricsProvider){e.writeHead(404,{"Content-Type":"text/plain"}),e.end("Not Found");return}e.writeHead(200,{"Content-Type":"text/plain; version=0.0.4; charset=utf-8"}),e.end(this._metricsProvider())}_handleHealthCheck(e){let t={status:"healthy",requests:this._requestCount,sessions:this._sessions.size,transport:"streamable-http"};this._healthChecker&&(t.liveness=this._healthChecker.checkLiveness()),e.writeHead(200,{"Content-Type":"application/json"}),e.end(JSON.stringify(t))}async _handleReadinessCheck(e){if(this._healthChecker){let t=await this._healthChecker.checkReadiness(),s="ok"===t.status?200:503;e.writeHead(s,{"Content-Type":"application/json"}),e.end(JSON.stringify(t))}else e.writeHead(200,{"Content-Type":"application/json"}),e.end(JSON.stringify({status:"ok",timestamp:new Date().toISOString(),components:{}}))}_updateSessionMetrics(){var e,t;null==(e=this._metrics)||e.gauge("streamable_http_active_sessions",this._sessions.size,{},"Active Streamable HTTP sessions");let s=0;for(let e of this._sessions.values())s+=e.notificationStreams.size;null==(t=this._metrics)||t.gauge("streamable_http_notification_streams",s,{},"Active SSE notification streams")}async stop(e){this._isShuttingDown=!0,this._stopRateLimitCleanup();let t=e??3e4;for(let e of this._sessions.values()){for(let t of e.notificationStreams)try{t.end()}catch{}e.notificationStreams.clear()}return this._sessions.clear(),new Promise(e=>{if(!this._server){this.log("info","Streamable HTTP transport stopped (no server)"),e();return}let s=setTimeout(()=>{this.log("warn","Streamable HTTP transport force-closing after timeout"),e()},t);this._server.close(()=>{clearTimeout(s),this.log("info","Streamable HTTP transport stopped"),e()})})}}},65(t){t.exports=e},561(e){e.exports=t},316(e){e.exports=s},61(e){e.exports=i},821(e){e.exports=n}},u={};function _(e){var t=u[e];if(void 0!==t)return t.exports;var s=u[e]={exports:{}};return d[e](s,s.exports,_),s.exports}_.d=(e,t)=>{for(var s in t)_.o(t,s)&&!_.o(e,s)&&Object.defineProperty(e,s,{enumerable:!0,get:t[s]})},_.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),(()=>{var e=_(61),t=_(65);let s=new p;class i{_level;_context;_pretty;static LEVEL_PRIORITY={debug:0,info:1,warn:2,error:3};constructor(e={}){this._level=e.level??"info",this._context=e.context??"SequentialThinking",this._pretty=e.pretty??!0}shouldLog(e){return i.LEVEL_PRIORITY[e]>=i.LEVEL_PRIORITY[this._level]}format(e){if(this._pretty){let t=e.meta?` ${JSON.stringify(e.meta)}`:"",s=e.requestId?` [${e.requestId}]`:"";return`[${e.timestamp}] [${e.level.toUpperCase()}]${e.context?` [${e.context}]`:""}${s} ${e.message}${t}`}return JSON.stringify(e)}log(e,t,i){var n;if(!this.shouldLog(e))return;let o=null==(n=s.getStore())?void 0:n.requestId,r={level:e,message:t,timestamp:new Date().toISOString(),context:this._context,meta:i,...o?{requestId:o}:{}};console.error(this.format(r))}debug(e,t){this.log("debug",e,t)}info(e,t){this.log("info",e,t)}warn(e,t){this.log("warn",e,t)}error(e,t){this.log("error",e,t)}createChild(e){return new i({level:this._level,context:`${this._context}:${e}`,pretty:this._pretty})}setLevel(e){this._level=e}getLevel(){return this._level}}var n=_(787),d=_(555);let{name:u,version:m}=JSON.parse(a(c(l((0,e.fileURLToPath)(import.meta.url)),"../package.json"),"utf-8")),g=process.argv.slice(2);async function f(e,t){var s;let{SseTransport:i}=await Promise.resolve().then(_.bind(_,504)),{createConnectionPool:n}=await Promise.resolve().then(_.bind(_,527)),o=parseInt(process.env.SSE_PORT||"3000",10),r=process.env.SSE_HOST||"localhost",a=t.getContainer().resolve("Metrics"),l="false"!==process.env.SSE_ENABLE_POOL,c=parseInt(process.env.SSE_MAX_SESSIONS||"100",10),h=parseInt(process.env.SSE_SESSION_TIMEOUT||"300000",10),p=l?n({maxSessions:c,sessionTimeout:h,logger:t._logger,serverFactory:async()=>{let{createServer:e}=await Promise.resolve().then(_.bind(_,65));return await e({autoDiscover:!0})}}):void 0,d=new i({port:o,host:r,corsOrigin:process.env.CORS_ORIGIN||"*",enableCors:"false"!==process.env.ENABLE_CORS,allowedHosts:null==(s=process.env.ALLOWED_HOSTS)?void 0:s.split(",").map(e=>e.trim()),metrics:a,connectionPool:p});await d.connect(e),S(async()=>{await d.stop(),await t.stop()}),t._logger.info(`Sequential Thinking MCP Server running on SSE transport at http://${r}:${o}`)}async function v(e,t){var s;let{StreamableHttpTransport:i}=await Promise.resolve().then(_.bind(_,756)),n=parseInt(process.env.STREAMABLE_HTTP_PORT||process.env.SSE_PORT||"3000",10),o=process.env.STREAMABLE_HTTP_HOST||process.env.SSE_HOST||"localhost",r=t.getContainer().resolve("Metrics"),a="false"!==process.env.STREAMABLE_HTTP_STATEFUL,l=new i({port:n,host:o,corsOrigin:process.env.CORS_ORIGIN||"*",enableCors:"false"!==process.env.ENABLE_CORS,allowedHosts:null==(s=process.env.ALLOWED_HOSTS)?void 0:s.split(",").map(e=>e.trim()),metrics:r,stateful:a});await l.connect(e),S(async()=>{await l.stop(),await t.stop()}),t._logger.info(`Sequential Thinking MCP Server running on Streamable HTTP transport at http://${o}:${n}`)}async function y(e,t){new r(e).listen();let s=async()=>{let e=setTimeout(()=>{t._logger.error("Graceful shutdown timed out after 30s - forcing exit"),process.exit(1)},3e4).unref();try{await t.stop(),clearTimeout(e),process.exit(0)}catch(e){t._logger.error("Error during shutdown",{error:(0,n.u1)(e)}),process.exit(1)}};process.once("SIGINT",()=>void s()),process.once("SIGTERM",()=>void s()),t._logger.info("Sequential Thinking MCP Server running on stdio")}function S(e){process.once("SIGINT",()=>{e().then(()=>process.exit(0)).catch(()=>process.exit(1))}),process.once("SIGTERM",()=>{e().then(()=>process.exit(0)).catch(()=>process.exit(1))})}(g.includes("--version")||g.includes("-v"))&&(console.log(`${u} v${m}`),process.exit(0)),(async function(){let e=new h({name:u,version:m,description:"Semantic Sequential Thinking MCP Server"},{adapter:new o,capabilities:{tools:{listChanged:!0}}}),s=await (0,t.initializeServer)();e.tool({name:"sequentialthinking_tools",description:d.iV.description,schema:d.ZK},async e=>s.processThought(e));let i=process.env.TRANSPORT_TYPE||"stdio";"sse"===i?await f(e,s):"streamable-http"===i?await v(e,s):await y(e,s)})().catch(e=>{new i({level:"error",context:"SequentialThinking",pretty:!0}).error("Fatal error running server",{error:(0,n.u1)(e)}),process.exit(1)})})();