@mcp-abap-adt/core 2.1.3 → 2.1.6

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 (438) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/bin/help.d.ts +6 -0
  3. package/dist/bin/help.d.ts.map +1 -0
  4. package/dist/bin/help.js +59 -0
  5. package/dist/bin/mcp-abap-adt-v2.d.ts +9 -0
  6. package/dist/bin/mcp-abap-adt-v2.d.ts.map +1 -0
  7. package/dist/bin/mcp-abap-adt-v2.js +247 -0
  8. package/dist/handlers/behavior_definition/readonly/handleGetBdef.d.ts +21 -0
  9. package/dist/handlers/behavior_definition/readonly/handleGetBdef.d.ts.map +1 -0
  10. package/dist/handlers/behavior_definition/readonly/handleGetBdef.js +24 -0
  11. package/dist/handlers/behavior_definition/readonly/handleGetBdef.js.map +1 -0
  12. package/dist/handlers/class/high/handleCreateLocalTestClass.d.ts.map +1 -1
  13. package/dist/handlers/class/high/handleCreateLocalTestClass.js +6 -1
  14. package/dist/handlers/class/high/handleCreateLocalTestClass.js.map +1 -1
  15. package/dist/handlers/class/high/handleGetUnitTest.d.ts +38 -0
  16. package/dist/handlers/class/high/handleGetUnitTest.d.ts.map +1 -0
  17. package/dist/handlers/class/high/handleGetUnitTest.js +73 -0
  18. package/dist/handlers/class/high/handleGetUnitTest.js.map +1 -0
  19. package/dist/handlers/class/high/handleRunUnitTest.d.ts +122 -0
  20. package/dist/handlers/class/high/handleRunUnitTest.d.ts.map +1 -0
  21. package/dist/handlers/class/high/handleRunUnitTest.js +133 -0
  22. package/dist/handlers/class/high/handleRunUnitTest.js.map +1 -0
  23. package/dist/handlers/class/readonly/handleGetClass.d.ts +23 -0
  24. package/dist/handlers/class/readonly/handleGetClass.d.ts.map +1 -0
  25. package/dist/handlers/class/readonly/handleGetClass.js +77 -0
  26. package/dist/handlers/class/readonly/handleGetClass.js.map +1 -0
  27. package/dist/handlers/data_element/readonly/handleGetDataElement.d.ts +23 -0
  28. package/dist/handlers/data_element/readonly/handleGetDataElement.d.ts.map +1 -0
  29. package/dist/handlers/data_element/readonly/handleGetDataElement.js +79 -0
  30. package/dist/handlers/data_element/readonly/handleGetDataElement.js.map +1 -0
  31. package/dist/handlers/domain/readonly/handleGetDomain.d.ts +23 -0
  32. package/dist/handlers/domain/readonly/handleGetDomain.d.ts.map +1 -0
  33. package/dist/handlers/domain/readonly/handleGetDomain.js +79 -0
  34. package/dist/handlers/domain/readonly/handleGetDomain.js.map +1 -0
  35. package/dist/handlers/enhancement/readonly/handleGetEnhancements.d.ts.map +1 -1
  36. package/dist/handlers/enhancement/readonly/handleGetEnhancements.js +7 -7
  37. package/dist/handlers/enhancement/readonly/handleGetEnhancements.js.map +1 -1
  38. package/dist/handlers/function/readonly/handleGetFunctionGroup.d.ts +23 -0
  39. package/dist/handlers/function/readonly/handleGetFunctionGroup.d.ts.map +1 -0
  40. package/dist/handlers/function/readonly/handleGetFunctionGroup.js +77 -0
  41. package/dist/handlers/function/readonly/handleGetFunctionGroup.js.map +1 -0
  42. package/dist/handlers/include/readonly/handleGetIncludesList.d.ts.map +1 -1
  43. package/dist/handlers/include/readonly/handleGetIncludesList.js +8 -5
  44. package/dist/handlers/include/readonly/handleGetIncludesList.js.map +1 -1
  45. package/dist/handlers/interface/readonly/handleGetInterface.d.ts +23 -0
  46. package/dist/handlers/interface/readonly/handleGetInterface.d.ts.map +1 -0
  47. package/dist/handlers/interface/readonly/handleGetInterface.js +77 -0
  48. package/dist/handlers/interface/readonly/handleGetInterface.js.map +1 -0
  49. package/dist/handlers/package/readonly/handleGetPackage.d.ts +22 -0
  50. package/dist/handlers/package/readonly/handleGetPackage.d.ts.map +1 -0
  51. package/dist/handlers/package/readonly/handleGetPackage.js +108 -0
  52. package/dist/handlers/package/readonly/handleGetPackage.js.map +1 -0
  53. package/dist/handlers/program/readonly/handleGetProgram.d.ts +23 -0
  54. package/dist/handlers/program/readonly/handleGetProgram.d.ts.map +1 -0
  55. package/dist/handlers/program/readonly/handleGetProgram.js +77 -0
  56. package/dist/handlers/program/readonly/handleGetProgram.js.map +1 -0
  57. package/dist/handlers/search/readonly/handleGetObjectsByType.d.ts.map +1 -1
  58. package/dist/handlers/search/readonly/handleGetObjectsByType.js +5 -1
  59. package/dist/handlers/search/readonly/handleGetObjectsByType.js.map +1 -1
  60. package/dist/handlers/search/readonly/handleGetObjectsList.d.ts.map +1 -1
  61. package/dist/handlers/search/readonly/handleGetObjectsList.js +8 -4
  62. package/dist/handlers/search/readonly/handleGetObjectsList.js.map +1 -1
  63. package/dist/handlers/service_definition/readonly/handleGetServiceDefinition.d.ts +18 -0
  64. package/dist/handlers/service_definition/readonly/handleGetServiceDefinition.d.ts.map +1 -0
  65. package/dist/handlers/service_definition/readonly/handleGetServiceDefinition.js +109 -0
  66. package/dist/handlers/service_definition/readonly/handleGetServiceDefinition.js.map +1 -0
  67. package/dist/handlers/structure/readonly/handleGetStructure.d.ts +23 -0
  68. package/dist/handlers/structure/readonly/handleGetStructure.d.ts.map +1 -0
  69. package/dist/handlers/structure/readonly/handleGetStructure.js +77 -0
  70. package/dist/handlers/structure/readonly/handleGetStructure.js.map +1 -0
  71. package/dist/handlers/system/readonly/handleGetObjectInfo.d.ts.map +1 -1
  72. package/dist/handlers/system/readonly/handleGetObjectInfo.js +8 -14
  73. package/dist/handlers/system/readonly/handleGetObjectInfo.js.map +1 -1
  74. package/dist/handlers/table/readonly/handleGetTable.d.ts +23 -0
  75. package/dist/handlers/table/readonly/handleGetTable.d.ts.map +1 -0
  76. package/dist/handlers/table/readonly/handleGetTable.js +77 -0
  77. package/dist/handlers/table/readonly/handleGetTable.js.map +1 -0
  78. package/dist/handlers/view/readonly/handleGetView.d.ts +33 -0
  79. package/dist/handlers/view/readonly/handleGetView.d.ts.map +1 -0
  80. package/dist/handlers/view/readonly/handleGetView.js +90 -0
  81. package/dist/handlers/view/readonly/handleGetView.js.map +1 -0
  82. package/dist/index.d.ts +126 -0
  83. package/dist/index.d.ts.map +1 -0
  84. package/dist/index.js +2979 -0
  85. package/dist/index.js.map +1 -0
  86. package/dist/lib/ServerConfigManager.d.ts +90 -0
  87. package/dist/lib/ServerConfigManager.d.ts.map +1 -0
  88. package/dist/lib/ServerConfigManager.js +237 -0
  89. package/dist/lib/ServerConfigManager.js.map +1 -0
  90. package/dist/lib/activationUtils.d.ts +59 -0
  91. package/dist/lib/activationUtils.d.ts.map +1 -0
  92. package/dist/lib/activationUtils.js +168 -0
  93. package/dist/lib/authBrokerFactory.d.ts +96 -0
  94. package/dist/lib/authBrokerFactory.d.ts.map +1 -0
  95. package/dist/lib/authBrokerFactory.js +531 -0
  96. package/dist/lib/authBrokerFactory.js.map +1 -0
  97. package/dist/lib/config/ServerConfig.d.ts +17 -0
  98. package/dist/lib/config/ServerConfig.d.ts.map +1 -0
  99. package/dist/lib/config/ServerConfig.js +7 -0
  100. package/dist/lib/config/ServerConfig.js.map +1 -0
  101. package/dist/lib/getFullCodeCache.d.ts +3 -0
  102. package/dist/lib/getFullCodeCache.d.ts.map +1 -0
  103. package/dist/lib/getFullCodeCache.js +56 -0
  104. package/dist/lib/handlers/handlers/base/BaseHandlerGroup.d.ts +36 -0
  105. package/dist/lib/handlers/handlers/base/BaseHandlerGroup.d.ts.map +1 -0
  106. package/dist/lib/handlers/handlers/base/BaseHandlerGroup.js +268 -0
  107. package/dist/lib/handlers/handlers/base/BaseHandlerGroup.js.map +1 -0
  108. package/dist/lib/handlers/handlers/examples/usage-example.d.ts +29 -0
  109. package/dist/lib/handlers/handlers/examples/usage-example.d.ts.map +1 -0
  110. package/dist/lib/handlers/handlers/examples/usage-example.js +119 -0
  111. package/dist/lib/handlers/handlers/examples/usage-example.js.map +1 -0
  112. package/dist/lib/handlers/handlers/groups/HighLevelHandlersGroup.d.ts +14 -0
  113. package/dist/lib/handlers/handlers/groups/HighLevelHandlersGroup.d.ts.map +1 -0
  114. package/dist/lib/handlers/handlers/groups/HighLevelHandlersGroup.js +322 -0
  115. package/dist/lib/handlers/handlers/groups/HighLevelHandlersGroup.js.map +1 -0
  116. package/dist/lib/handlers/handlers/groups/LowLevelHandlersGroup.d.ts +14 -0
  117. package/dist/lib/handlers/handlers/groups/LowLevelHandlersGroup.d.ts.map +1 -0
  118. package/dist/lib/handlers/handlers/groups/LowLevelHandlersGroup.js +1214 -0
  119. package/dist/lib/handlers/handlers/groups/LowLevelHandlersGroup.js.map +1 -0
  120. package/dist/lib/handlers/handlers/groups/ReadOnlyHandlersGroup.d.ts +14 -0
  121. package/dist/lib/handlers/handlers/groups/ReadOnlyHandlersGroup.d.ts.map +1 -0
  122. package/dist/lib/handlers/handlers/groups/ReadOnlyHandlersGroup.js +232 -0
  123. package/dist/lib/handlers/handlers/groups/ReadOnlyHandlersGroup.js.map +1 -0
  124. package/dist/lib/handlers/handlers/groups/SearchHandlersGroup.d.ts +14 -0
  125. package/dist/lib/handlers/handlers/groups/SearchHandlersGroup.d.ts.map +1 -0
  126. package/dist/lib/handlers/handlers/groups/SearchHandlersGroup.js +57 -0
  127. package/dist/lib/handlers/handlers/groups/SearchHandlersGroup.js.map +1 -0
  128. package/dist/lib/handlers/handlers/groups/SystemHandlersGroup.d.ts +14 -0
  129. package/dist/lib/handlers/handlers/groups/SystemHandlersGroup.d.ts.map +1 -0
  130. package/dist/lib/handlers/handlers/groups/SystemHandlersGroup.js +176 -0
  131. package/dist/lib/handlers/handlers/groups/SystemHandlersGroup.js.map +1 -0
  132. package/dist/lib/handlers/handlers/groups/index.d.ts +13 -0
  133. package/dist/lib/handlers/handlers/groups/index.d.ts.map +1 -0
  134. package/dist/lib/handlers/handlers/groups/index.js +21 -0
  135. package/dist/lib/handlers/handlers/groups/index.js.map +1 -0
  136. package/dist/lib/handlers/handlers/index.d.ts +14 -0
  137. package/dist/lib/handlers/handlers/index.d.ts.map +1 -0
  138. package/dist/lib/handlers/handlers/index.js +37 -0
  139. package/dist/lib/handlers/handlers/index.js.map +1 -0
  140. package/dist/lib/handlers/handlers/interfaces.d.ts +67 -0
  141. package/dist/lib/handlers/handlers/interfaces.d.ts.map +1 -0
  142. package/dist/lib/handlers/handlers/interfaces.js +3 -0
  143. package/dist/lib/handlers/handlers/interfaces.js.map +1 -0
  144. package/dist/lib/handlers/handlers/registry/CompositeHandlersRegistry.d.ts +49 -0
  145. package/dist/lib/handlers/handlers/registry/CompositeHandlersRegistry.d.ts.map +1 -0
  146. package/dist/lib/handlers/handlers/registry/CompositeHandlersRegistry.js +88 -0
  147. package/dist/lib/handlers/handlers/registry/CompositeHandlersRegistry.js.map +1 -0
  148. package/dist/lib/runtimeConfig.d.ts +20 -0
  149. package/dist/lib/runtimeConfig.d.ts.map +1 -0
  150. package/dist/lib/runtimeConfig.js +130 -0
  151. package/dist/lib/runtimeConfig.js.map +1 -0
  152. package/dist/lib/servers/BaseMcpServer.d.ts +56 -0
  153. package/dist/lib/servers/BaseMcpServer.d.ts.map +1 -0
  154. package/dist/lib/servers/BaseMcpServer.js +198 -0
  155. package/dist/lib/servers/BaseMcpServer.js.map +1 -0
  156. package/dist/lib/servers/ConnectionContext.d.ts +20 -0
  157. package/dist/lib/servers/ConnectionContext.d.ts.map +1 -0
  158. package/dist/lib/servers/ConnectionContext.js +3 -0
  159. package/dist/lib/servers/ConnectionContext.js.map +1 -0
  160. package/dist/lib/servers/SseServer.d.ts +32 -0
  161. package/dist/lib/servers/SseServer.d.ts.map +1 -0
  162. package/dist/lib/servers/SseServer.js +139 -0
  163. package/dist/lib/servers/SseServer.js.map +1 -0
  164. package/dist/lib/servers/StdioServer.d.ts +20 -0
  165. package/dist/lib/servers/StdioServer.d.ts.map +1 -0
  166. package/dist/lib/servers/StdioServer.js +32 -0
  167. package/dist/lib/servers/StdioServer.js.map +1 -0
  168. package/dist/lib/servers/StreamableHttpServer.d.ts +30 -0
  169. package/dist/lib/servers/StreamableHttpServer.d.ts.map +1 -0
  170. package/dist/lib/servers/StreamableHttpServer.js +83 -0
  171. package/dist/lib/servers/StreamableHttpServer.js.map +1 -0
  172. package/dist/lib/servers/handlers/base/BaseHandlerGroup.d.ts +36 -0
  173. package/dist/lib/servers/handlers/base/BaseHandlerGroup.d.ts.map +1 -0
  174. package/dist/lib/servers/handlers/base/BaseHandlerGroup.js +268 -0
  175. package/dist/lib/servers/handlers/base/BaseHandlerGroup.js.map +1 -0
  176. package/dist/lib/servers/handlers/examples/usage-example.d.ts +29 -0
  177. package/dist/lib/servers/handlers/examples/usage-example.d.ts.map +1 -0
  178. package/dist/lib/servers/handlers/examples/usage-example.js +119 -0
  179. package/dist/lib/servers/handlers/examples/usage-example.js.map +1 -0
  180. package/dist/lib/servers/handlers/groups/HighLevelHandlersGroup.d.ts +14 -0
  181. package/dist/lib/servers/handlers/groups/HighLevelHandlersGroup.d.ts.map +1 -0
  182. package/dist/lib/servers/handlers/groups/HighLevelHandlersGroup.js +322 -0
  183. package/dist/lib/servers/handlers/groups/HighLevelHandlersGroup.js.map +1 -0
  184. package/dist/lib/servers/handlers/groups/LowLevelHandlersGroup.d.ts +14 -0
  185. package/dist/lib/servers/handlers/groups/LowLevelHandlersGroup.d.ts.map +1 -0
  186. package/dist/lib/servers/handlers/groups/LowLevelHandlersGroup.js +1214 -0
  187. package/dist/lib/servers/handlers/groups/LowLevelHandlersGroup.js.map +1 -0
  188. package/dist/lib/servers/handlers/groups/ReadOnlyHandlersGroup.d.ts +14 -0
  189. package/dist/lib/servers/handlers/groups/ReadOnlyHandlersGroup.d.ts.map +1 -0
  190. package/dist/lib/servers/handlers/groups/ReadOnlyHandlersGroup.js +232 -0
  191. package/dist/lib/servers/handlers/groups/ReadOnlyHandlersGroup.js.map +1 -0
  192. package/dist/lib/servers/handlers/groups/SearchHandlersGroup.d.ts +14 -0
  193. package/dist/lib/servers/handlers/groups/SearchHandlersGroup.d.ts.map +1 -0
  194. package/dist/lib/servers/handlers/groups/SearchHandlersGroup.js +57 -0
  195. package/dist/lib/servers/handlers/groups/SearchHandlersGroup.js.map +1 -0
  196. package/dist/lib/servers/handlers/groups/SystemHandlersGroup.d.ts +14 -0
  197. package/dist/lib/servers/handlers/groups/SystemHandlersGroup.d.ts.map +1 -0
  198. package/dist/lib/servers/handlers/groups/SystemHandlersGroup.js +176 -0
  199. package/dist/lib/servers/handlers/groups/SystemHandlersGroup.js.map +1 -0
  200. package/dist/lib/servers/handlers/groups/index.d.ts +13 -0
  201. package/dist/lib/servers/handlers/groups/index.d.ts.map +1 -0
  202. package/dist/lib/servers/handlers/groups/index.js +21 -0
  203. package/dist/lib/servers/handlers/groups/index.js.map +1 -0
  204. package/dist/lib/servers/handlers/index.d.ts +14 -0
  205. package/dist/lib/servers/handlers/index.d.ts.map +1 -0
  206. package/dist/lib/servers/handlers/index.js +37 -0
  207. package/dist/lib/servers/handlers/index.js.map +1 -0
  208. package/dist/lib/servers/handlers/interfaces.d.ts +67 -0
  209. package/dist/lib/servers/handlers/interfaces.d.ts.map +1 -0
  210. package/dist/lib/servers/handlers/interfaces.js +3 -0
  211. package/dist/lib/servers/handlers/interfaces.js.map +1 -0
  212. package/dist/lib/servers/handlers/registry/CompositeHandlersRegistry.d.ts +49 -0
  213. package/dist/lib/servers/handlers/registry/CompositeHandlersRegistry.d.ts.map +1 -0
  214. package/dist/lib/servers/handlers/registry/CompositeHandlersRegistry.js +88 -0
  215. package/dist/lib/servers/handlers/registry/CompositeHandlersRegistry.js.map +1 -0
  216. package/dist/lib/servers/index.d.ts +5 -0
  217. package/dist/lib/servers/index.d.ts.map +1 -0
  218. package/dist/lib/servers/index.js +21 -0
  219. package/dist/lib/servers/index.js.map +1 -0
  220. package/dist/lib/servers/launcher.d.ts +2 -0
  221. package/dist/lib/servers/launcher.d.ts.map +1 -0
  222. package/dist/lib/servers/launcher.js +123 -0
  223. package/dist/lib/servers/launcher.js.map +1 -0
  224. package/dist/lib/servers/mcp_handlers.d.ts +25 -0
  225. package/dist/lib/servers/mcp_handlers.d.ts.map +1 -0
  226. package/dist/lib/servers/mcp_handlers.js +822 -0
  227. package/dist/lib/servers/mcp_handlers.js.map +1 -0
  228. package/dist/lib/servers/mcp_server.d.ts +7 -0
  229. package/dist/lib/servers/mcp_server.d.ts.map +1 -0
  230. package/dist/lib/servers/mcp_server.js +12 -0
  231. package/dist/lib/servers/utils.d.ts +42 -0
  232. package/dist/lib/servers/utils.d.ts.map +1 -0
  233. package/dist/lib/servers/utils.js +620 -0
  234. package/dist/lib/servers/utils.js.map +1 -0
  235. package/dist/lib/servers/v2/__tests__/unit/McpServer.test.d.ts +7 -0
  236. package/dist/lib/servers/v2/__tests__/unit/McpServer.test.d.ts.map +1 -0
  237. package/dist/lib/servers/v2/__tests__/unit/McpServer.test.js +218 -0
  238. package/dist/lib/servers/v2/connection/LocalConnectionProvider.d.ts +20 -0
  239. package/dist/lib/servers/v2/connection/LocalConnectionProvider.d.ts.map +1 -0
  240. package/dist/lib/servers/v2/connection/LocalConnectionProvider.js +70 -0
  241. package/dist/lib/servers/v2/connection/RemoteConnectionProvider.d.ts +21 -0
  242. package/dist/lib/servers/v2/connection/RemoteConnectionProvider.d.ts.map +1 -0
  243. package/dist/lib/servers/v2/connection/RemoteConnectionProvider.js +36 -0
  244. package/dist/lib/servers/v2/connection/index.d.ts +6 -0
  245. package/dist/lib/servers/v2/connection/index.d.ts.map +1 -0
  246. package/dist/lib/servers/v2/connection/index.js +10 -0
  247. package/dist/lib/servers/v2/factory/AuthBrokerFactory.d.ts +29 -0
  248. package/dist/lib/servers/v2/factory/AuthBrokerFactory.d.ts.map +1 -0
  249. package/dist/lib/servers/v2/factory/AuthBrokerFactory.js +79 -0
  250. package/dist/lib/servers/v2/factory/LocalModeFactory.d.ts +38 -0
  251. package/dist/lib/servers/v2/factory/LocalModeFactory.d.ts.map +1 -0
  252. package/dist/lib/servers/v2/factory/LocalModeFactory.js +38 -0
  253. package/dist/lib/servers/v2/factory/index.d.ts +6 -0
  254. package/dist/lib/servers/v2/factory/index.d.ts.map +1 -0
  255. package/dist/lib/servers/v2/factory/index.js +10 -0
  256. package/dist/lib/servers/v2/index.d.ts +9 -0
  257. package/dist/lib/servers/v2/index.d.ts.map +1 -0
  258. package/dist/lib/servers/v2/index.js +27 -0
  259. package/dist/lib/servers/v2/index.js.map +1 -0
  260. package/dist/lib/servers/v2/interfaces/connection.d.ts +188 -0
  261. package/dist/lib/servers/v2/interfaces/connection.d.ts.map +1 -0
  262. package/dist/lib/servers/v2/interfaces/connection.js +7 -0
  263. package/dist/lib/servers/v2/interfaces/index.d.ts +10 -0
  264. package/dist/lib/servers/v2/interfaces/index.d.ts.map +1 -0
  265. package/dist/lib/servers/v2/interfaces/index.js +25 -0
  266. package/dist/lib/servers/v2/interfaces/protocol.d.ts +30 -0
  267. package/dist/lib/servers/v2/interfaces/protocol.d.ts.map +1 -0
  268. package/dist/lib/servers/v2/interfaces/protocol.js +7 -0
  269. package/dist/lib/servers/v2/interfaces/session.d.ts +98 -0
  270. package/dist/lib/servers/v2/interfaces/session.d.ts.map +1 -0
  271. package/dist/lib/servers/v2/interfaces/session.js +7 -0
  272. package/dist/lib/servers/v2/interfaces/transport.d.ts +88 -0
  273. package/dist/lib/servers/v2/interfaces/transport.d.ts.map +1 -0
  274. package/dist/lib/servers/v2/interfaces/transport.js +7 -0
  275. package/dist/lib/servers/v2/protocol/ProtocolHandler.d.ts +21 -0
  276. package/dist/lib/servers/v2/protocol/ProtocolHandler.d.ts.map +1 -0
  277. package/dist/lib/servers/v2/protocol/ProtocolHandler.js +77 -0
  278. package/dist/lib/servers/v2/protocol/index.d.ts +5 -0
  279. package/dist/lib/servers/v2/protocol/index.d.ts.map +1 -0
  280. package/dist/lib/servers/v2/protocol/index.js +8 -0
  281. package/dist/lib/servers/v2/server/McpServer.d.ts +76 -0
  282. package/dist/lib/servers/v2/server/McpServer.d.ts.map +1 -0
  283. package/dist/lib/servers/v2/server/McpServer.js +243 -0
  284. package/dist/lib/servers/v2/server/index.d.ts +5 -0
  285. package/dist/lib/servers/v2/server/index.d.ts.map +1 -0
  286. package/dist/lib/servers/v2/server/index.js +8 -0
  287. package/dist/lib/servers/v2/session/SessionManager.d.ts +40 -0
  288. package/dist/lib/servers/v2/session/SessionManager.d.ts.map +1 -0
  289. package/dist/lib/servers/v2/session/SessionManager.js +136 -0
  290. package/dist/lib/servers/v2/session/index.d.ts +5 -0
  291. package/dist/lib/servers/v2/session/index.d.ts.map +1 -0
  292. package/dist/lib/servers/v2/session/index.js +8 -0
  293. package/dist/lib/servers/v2/transports/SseTransport.d.ts +49 -0
  294. package/dist/lib/servers/v2/transports/SseTransport.d.ts.map +1 -0
  295. package/dist/lib/servers/v2/transports/SseTransport.js +89 -0
  296. package/dist/lib/servers/v2/transports/StdioTransport.d.ts +31 -0
  297. package/dist/lib/servers/v2/transports/StdioTransport.d.ts.map +1 -0
  298. package/dist/lib/servers/v2/transports/StdioTransport.js +91 -0
  299. package/dist/lib/servers/v2/transports/StreamableHttpTransport.d.ts +51 -0
  300. package/dist/lib/servers/v2/transports/StreamableHttpTransport.d.ts.map +1 -0
  301. package/dist/lib/servers/v2/transports/StreamableHttpTransport.js +147 -0
  302. package/dist/lib/servers/v2/transports/index.d.ts +7 -0
  303. package/dist/lib/servers/v2/transports/index.d.ts.map +1 -0
  304. package/dist/lib/servers/v2/transports/index.js +12 -0
  305. package/dist/lib/servers/v2/types/common.d.ts +17 -0
  306. package/dist/lib/servers/v2/types/common.d.ts.map +1 -0
  307. package/dist/lib/servers/v2/types/common.js +6 -0
  308. package/dist/lib/servers/v2/types/common.js.map +1 -0
  309. package/dist/lib/servers/v2/types/index.d.ts +8 -0
  310. package/dist/lib/servers/v2/types/index.d.ts.map +1 -0
  311. package/dist/lib/servers/v2/types/index.js +24 -0
  312. package/dist/lib/servers/v2/types/index.js.map +1 -0
  313. package/dist/lib/servers/v2/types/transport.d.ts +28 -0
  314. package/dist/lib/servers/v2/types/transport.d.ts.map +1 -0
  315. package/dist/lib/servers/v2/types/transport.js +8 -0
  316. package/dist/lib/servers/v2/types/transport.js.map +1 -0
  317. package/dist/lib/servers/v2/utils/StdioLogger.d.ts +17 -0
  318. package/dist/lib/servers/v2/utils/StdioLogger.d.ts.map +1 -0
  319. package/dist/lib/servers/v2/utils/StdioLogger.js +33 -0
  320. package/dist/lib/servers/v2/utils/StdioLogger.js.map +1 -0
  321. package/dist/lib/stores/UnixFileServiceKeyStore.d.ts +42 -0
  322. package/dist/lib/stores/UnixFileServiceKeyStore.d.ts.map +1 -0
  323. package/dist/lib/stores/UnixFileServiceKeyStore.js +53 -0
  324. package/dist/lib/stores/UnixFileSessionStore.d.ts +54 -0
  325. package/dist/lib/stores/UnixFileSessionStore.d.ts.map +1 -0
  326. package/dist/lib/stores/UnixFileSessionStore.js +70 -0
  327. package/dist/lib/stores/WindowsFileServiceKeyStore.d.ts +42 -0
  328. package/dist/lib/stores/WindowsFileServiceKeyStore.d.ts.map +1 -0
  329. package/dist/lib/stores/WindowsFileServiceKeyStore.js +53 -0
  330. package/dist/lib/stores/WindowsFileSessionStore.d.ts +54 -0
  331. package/dist/lib/stores/WindowsFileSessionStore.d.ts.map +1 -0
  332. package/dist/lib/stores/WindowsFileSessionStore.js +70 -0
  333. package/dist/lib/toolsRegistry.d.ts +13 -0
  334. package/dist/lib/toolsRegistry.d.ts.map +1 -0
  335. package/dist/lib/toolsRegistry.js +410 -0
  336. package/dist/lib/transportConfig.d.ts +27 -0
  337. package/dist/lib/transportConfig.d.ts.map +1 -0
  338. package/dist/lib/transportConfig.js +124 -0
  339. package/dist/lib/transports/stdio.d.ts +10 -0
  340. package/dist/lib/transports/stdio.d.ts.map +1 -0
  341. package/dist/lib/transports/stdio.js +73 -0
  342. package/dist/lib/utils.d.ts +37 -0
  343. package/dist/lib/utils.d.ts.map +1 -1
  344. package/dist/lib/utils.js +83 -0
  345. package/dist/lib/utils.js.map +1 -1
  346. package/dist/lib/yamlConfig.d.ts +59 -0
  347. package/dist/lib/yamlConfig.d.ts.map +1 -0
  348. package/dist/lib/yamlConfig.js +349 -0
  349. package/dist/lib/yamlConfig.js.map +1 -0
  350. package/dist/server/launcher.js +49 -0
  351. package/dist/server/launcher.js.map +1 -1
  352. package/dist/server/v1/AuthBrokerConfig.d.ts +19 -0
  353. package/dist/server/v1/AuthBrokerConfig.d.ts.map +1 -0
  354. package/dist/server/v1/AuthBrokerConfig.js +44 -0
  355. package/dist/server/v1/AuthBrokerConfig.js.map +1 -0
  356. package/dist/server/v1/IServerConfig.d.ts +17 -0
  357. package/dist/server/v1/IServerConfig.d.ts.map +1 -0
  358. package/dist/server/v1/IServerConfig.js +7 -0
  359. package/dist/server/v1/IServerConfig.js.map +1 -0
  360. package/dist/server/v1/ServerConfig.d.ts +16 -0
  361. package/dist/server/v1/ServerConfig.d.ts.map +1 -0
  362. package/dist/server/v1/ServerConfig.js +6 -0
  363. package/dist/server/v1/ServerConfig.js.map +1 -0
  364. package/dist/server/v1/embeddable-server.d.ts +89 -0
  365. package/dist/server/v1/embeddable-server.d.ts.map +1 -0
  366. package/dist/server/v1/embeddable-server.js +83 -0
  367. package/dist/server/v1/embeddable-server.js.map +1 -0
  368. package/dist/server/v1/index.d.ts +30 -0
  369. package/dist/server/v1/index.d.ts.map +1 -0
  370. package/dist/server/v1/index.js +65 -0
  371. package/dist/server/v1/index.js.map +1 -0
  372. package/dist/server/v1/legacy-server.d.ts +141 -0
  373. package/dist/server/v1/legacy-server.d.ts.map +1 -0
  374. package/dist/server/v1/legacy-server.js +2099 -0
  375. package/dist/server/v1/legacy-server.js.map +1 -0
  376. package/dist/server/v1/mcp_handlers.d.ts +19 -0
  377. package/dist/server/v1/mcp_handlers.d.ts.map +1 -0
  378. package/dist/server/v1/mcp_handlers.js +85 -0
  379. package/dist/server/v1/mcp_handlers.js.map +1 -0
  380. package/dist/server/v2/AuthBrokerConfig.d.ts +22 -0
  381. package/dist/server/v2/AuthBrokerConfig.d.ts.map +1 -0
  382. package/dist/server/v2/AuthBrokerConfig.js +46 -0
  383. package/dist/server/v2/AuthBrokerConfig.js.map +1 -0
  384. package/dist/server/v2/BaseMcpServer.d.ts +67 -0
  385. package/dist/server/v2/BaseMcpServer.d.ts.map +1 -0
  386. package/dist/server/v2/BaseMcpServer.js +273 -0
  387. package/dist/server/v2/BaseMcpServer.js.map +1 -0
  388. package/dist/server/v2/ConnectionContext.d.ts +20 -0
  389. package/dist/server/v2/ConnectionContext.d.ts.map +1 -0
  390. package/dist/server/v2/ConnectionContext.js +3 -0
  391. package/dist/server/v2/ConnectionContext.js.map +1 -0
  392. package/dist/server/v2/IHttpApplication.d.ts +42 -0
  393. package/dist/server/v2/IHttpApplication.d.ts.map +1 -0
  394. package/dist/server/v2/IHttpApplication.js +3 -0
  395. package/dist/server/v2/IHttpApplication.js.map +1 -0
  396. package/dist/server/v2/IServerConfig.d.ts +15 -0
  397. package/dist/server/v2/IServerConfig.d.ts.map +1 -0
  398. package/dist/server/v2/IServerConfig.js +7 -0
  399. package/dist/server/v2/IServerConfig.js.map +1 -0
  400. package/dist/server/v2/ServerConfig.d.ts +16 -0
  401. package/dist/server/v2/ServerConfig.d.ts.map +1 -0
  402. package/dist/server/v2/ServerConfig.js +6 -0
  403. package/dist/server/v2/ServerConfig.js.map +1 -0
  404. package/dist/server/v2/SseServer.d.ts +95 -0
  405. package/dist/server/v2/SseServer.d.ts.map +1 -0
  406. package/dist/server/v2/SseServer.js +217 -0
  407. package/dist/server/v2/SseServer.js.map +1 -0
  408. package/dist/server/v2/StdioServer.d.ts +20 -0
  409. package/dist/server/v2/StdioServer.d.ts.map +1 -0
  410. package/dist/server/v2/StdioServer.js +32 -0
  411. package/dist/server/v2/StdioServer.js.map +1 -0
  412. package/dist/server/v2/StreamableHttpServer.d.ts +94 -0
  413. package/dist/server/v2/StreamableHttpServer.d.ts.map +1 -0
  414. package/dist/server/v2/StreamableHttpServer.js +170 -0
  415. package/dist/server/v2/StreamableHttpServer.js.map +1 -0
  416. package/dist/server/v2/index.d.ts +6 -0
  417. package/dist/server/v2/index.d.ts.map +1 -0
  418. package/dist/server/v2/index.js +22 -0
  419. package/dist/server/v2/index.js.map +1 -0
  420. package/dist/server/v2/launcher.d.ts +2 -0
  421. package/dist/server/v2/launcher.d.ts.map +1 -0
  422. package/dist/server/v2/launcher.js +181 -0
  423. package/dist/server/v2/launcher.js.map +1 -0
  424. package/dist/server/v2/mcp_handlers.d.ts +25 -0
  425. package/dist/server/v2/mcp_handlers.d.ts.map +1 -0
  426. package/dist/server/v2/mcp_handlers.js +828 -0
  427. package/dist/server/v2/mcp_handlers.js.map +1 -0
  428. package/dist/server/v2/utils.d.ts +42 -0
  429. package/dist/server/v2/utils.d.ts.map +1 -0
  430. package/dist/server/v2/utils.js +620 -0
  431. package/dist/server/v2/utils.js.map +1 -0
  432. package/dist/tools/test-v2-server-stdio-compiled.js +132 -0
  433. package/dist/utils/lockStateManager.d.ts +2 -12
  434. package/dist/utils/lockStateManager.d.ts.map +1 -1
  435. package/dist/utils/lockStateManager.js +4 -63
  436. package/dist/utils/lockStateManager.js.map +1 -1
  437. package/docs/user-guide/AVAILABLE_TOOLS.md +1 -1
  438. package/package.json +1 -1
@@ -0,0 +1,2099 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ // Simple stdio mode detection (like reference implementation)
4
+ // No output suppression needed - dotenv removed, manual .env parsing used
5
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ var desc = Object.getOwnPropertyDescriptor(m, k);
8
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
9
+ desc = { enumerable: true, get: function() { return m[k]; } };
10
+ }
11
+ Object.defineProperty(o, k2, desc);
12
+ }) : (function(o, m, k, k2) {
13
+ if (k2 === undefined) k2 = k;
14
+ o[k2] = m[k];
15
+ }));
16
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
17
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
18
+ }) : function(o, v) {
19
+ o["default"] = v;
20
+ });
21
+ var __importStar = (this && this.__importStar) || (function () {
22
+ var ownKeys = function(o) {
23
+ ownKeys = Object.getOwnPropertyNames || function (o) {
24
+ var ar = [];
25
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
26
+ return ar;
27
+ };
28
+ return ownKeys(o);
29
+ };
30
+ return function (mod) {
31
+ if (mod && mod.__esModule) return mod;
32
+ var result = {};
33
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
34
+ __setModuleDefault(result, mod);
35
+ return result;
36
+ };
37
+ })();
38
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
39
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
40
+ };
41
+ var __importDefault = (this && this.__importDefault) || function (mod) {
42
+ return (mod && mod.__esModule) ? mod : { "default": mod };
43
+ };
44
+ Object.defineProperty(exports, "__esModule", { value: true });
45
+ exports.mcp_abap_adt_server = exports.createDefaultHandlerExporter = exports.HandlerExporter = exports.getConfig = exports.setSapConfigOverride = void 0;
46
+ exports.setAbapConnectionOverride = setAbapConnectionOverride;
47
+ const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
48
+ const mcp_handlers_1 = require("./mcp_handlers");
49
+ const path_1 = __importDefault(require("path"));
50
+ const os = __importStar(require("os"));
51
+ const crypto_1 = require("crypto");
52
+ const header_validator_1 = require("@mcp-abap-adt/header-validator");
53
+ const interfaces_1 = require("@mcp-abap-adt/interfaces");
54
+ const index_1 = require("../../lib/auth/index");
55
+ const AuthBrokerConfig_js_1 = require("./AuthBrokerConfig.js");
56
+ const platformPaths_1 = require("../../lib/stores/platformPaths");
57
+ const runtimeConfig_1 = require("../../lib/config/runtimeConfig");
58
+ const yamlConfig_1 = require("../../lib/config/yamlConfig");
59
+ const index_2 = require("../../lib/config/index");
60
+ // Import handler functions
61
+ // Import handler functions
62
+ // New low-level handlers imports
63
+ // Import shared utility functions and types
64
+ const utils_1 = require("../../lib/utils");
65
+ const config_js_1 = require("../../lib/config.js");
66
+ Object.defineProperty(exports, "getConfig", { enumerable: true, get: function () { return config_js_1.getConfig; } });
67
+ Object.defineProperty(exports, "setSapConfigOverride", { enumerable: true, get: function () { return config_js_1.setSapConfigOverride; } });
68
+ const connection_1 = require("@mcp-abap-adt/connection");
69
+ const loggerAdapter_1 = require("../../lib/loggerAdapter");
70
+ // Import logger
71
+ const logger_1 = require("../../lib/logger");
72
+ // import { defaultLogger as logger } from "@mcp-abap-adt/logger";
73
+ // Import tool registry
74
+ // Import TOOL_DEFINITION from handlers
75
+ // New low-level handlers TOOL_DEFINITION imports
76
+ // --- ENV FILE LOADING LOGIC ---
77
+ const fs_1 = __importDefault(require("fs"));
78
+ /**
79
+ * Additional help sections specific to v1 server
80
+ */
81
+ const V1_HELP_SECTIONS = `
82
+ ENVIRONMENT VARIABLES:
83
+ DEBUG_AUTH_LOG Enable debug logging for auth-broker (true|false)
84
+ Default: false (only info messages shown)
85
+ DEBUG_AUTH_BROKER Alias for DEBUG_AUTH_LOG
86
+ DEBUG_HTTP_REQUESTS Enable logging of HTTP requests (true|false)
87
+ DEBUG_CONNECTORS Enable debug logging for connection layer (true|false)
88
+ DEBUG_HANDLERS Enable debug logging for MCP handlers (true|false)
89
+ AUTH_BROKER_PATH Custom paths for service keys and sessions
90
+ Unix: colon-separated (e.g., /path1:/path2)
91
+ Windows: semicolon-separated (e.g., C:\\\\path1;C:\\\\path2)
92
+
93
+ SAP CONNECTION (.env file):
94
+ SAP_URL SAP system URL (required)
95
+ SAP_CLIENT SAP client number (required)
96
+ SAP_AUTH_TYPE Authentication type: basic|jwt (default: basic)
97
+ SAP_USERNAME SAP username (required for basic auth)
98
+ SAP_PASSWORD SAP password (required for basic auth)
99
+ SAP_JWT_TOKEN JWT token (required for jwt auth)
100
+
101
+ GENERATING .ENV FROM SERVICE KEY:
102
+ Install connection package: npm install -g @mcp-abap-adt/connection
103
+ Generate .env: sap-abap-auth auth -k path/to/service-key.json
104
+
105
+ SERVICE KEYS (Destination-Based Authentication):
106
+ Store service keys in platform-specific locations:
107
+ Linux/macOS: ~/.config/mcp-abap-adt/service-keys/{destination}.json
108
+ Windows: %USERPROFILE%\\\\Documents\\\\mcp-abap-adt\\\\service-keys\\\\{destination}.json
109
+
110
+ Using Destinations:
111
+ In HTTP headers: x-mcp-destination: TRIAL
112
+ Or via CLI: mcp-abap-adt --mcp=TRIAL
113
+
114
+ CLINE CONFIGURATION EXAMPLES (~/.cline/mcp.json):
115
+
116
+ 1. Stdio with .env file:
117
+ {
118
+ "mcpServers": {
119
+ "mcp-abap-adt": {
120
+ "type": "stdio",
121
+ "command": "mcp-abap-adt",
122
+ "args": ["--env=/path/to/.env"]
123
+ }
124
+ }
125
+ }
126
+
127
+ 2. Stdio with MCP destination (service key):
128
+ {
129
+ "mcpServers": {
130
+ "mcp-abap-adt": {
131
+ "type": "stdio",
132
+ "command": "mcp-abap-adt",
133
+ "args": ["--mcp=TRIAL"]
134
+ }
135
+ }
136
+ }
137
+
138
+ 3. SSE transport:
139
+ {
140
+ "mcpServers": {
141
+ "mcp-abap-adt": {
142
+ "type": "sse",
143
+ "url": "http://localhost:3001/sse"
144
+ }
145
+ }
146
+ }
147
+
148
+ DOCUMENTATION:
149
+ https://github.com/fr0ster/mcp-abap-adt
150
+ Installation: docs/installation/INSTALLATION.md
151
+ Configuration: docs/user-guide/CLIENT_CONFIGURATION.md
152
+ Available Tools: docs/user-guide/AVAILABLE_TOOLS.md
153
+ `;
154
+ /**
155
+ * Display help message using unified ServerConfigManager
156
+ */
157
+ function showHelp() {
158
+ console.log(index_2.ServerConfigManager.generateHelp(V1_HELP_SECTIONS));
159
+ process.exit(0);
160
+ }
161
+ // Check for version/help flags
162
+ if (process.argv.includes("--version") || process.argv.includes("-v")) {
163
+ const packageJsonPath = path_1.default.join(__dirname, "..", "..", "..", "package.json");
164
+ const packageJson = JSON.parse(fs_1.default.readFileSync(packageJsonPath, "utf8"));
165
+ console.log(packageJson.version);
166
+ process.exit(0);
167
+ }
168
+ if (process.argv.includes("--help") || process.argv.includes("-h")) {
169
+ showHelp();
170
+ }
171
+ // Load YAML config if --config parameter is provided
172
+ // YAML config values are applied to process.argv (command-line args override YAML)
173
+ const configPath = (0, yamlConfig_1.parseConfigArg)();
174
+ if (configPath) {
175
+ try {
176
+ // Generate template if file doesn't exist
177
+ const templateGenerated = (0, yamlConfig_1.generateConfigTemplateIfNeeded)(configPath);
178
+ // If template was just generated, exit successfully
179
+ // User needs to edit the file before running the server
180
+ if (templateGenerated) {
181
+ if (process.platform === 'win32') {
182
+ setTimeout(() => process.exit(0), 100);
183
+ }
184
+ else {
185
+ process.exit(0);
186
+ }
187
+ }
188
+ // Load and apply YAML config (only if file exists)
189
+ const yamlConfig = (0, yamlConfig_1.loadYamlConfig)(configPath);
190
+ if (yamlConfig) {
191
+ (0, yamlConfig_1.applyYamlConfigToArgs)(yamlConfig);
192
+ // Only write to stderr if not in stdio mode (stdio mode requires clean JSON only)
193
+ const isStdioMode = process.env.MCP_TRANSPORT === "stdio" || !process.stdin.isTTY;
194
+ if (!isStdioMode) {
195
+ process.stderr.write(`[MCP-CONFIG] Loaded and validated configuration from: ${configPath}\n`);
196
+ }
197
+ }
198
+ }
199
+ catch (error) {
200
+ const errorMsg = `Failed to load YAML config: ${error instanceof Error ? error.message : String(error)}`;
201
+ process.stderr.write(`[MCP-CONFIG] ✗ ERROR: ${errorMsg}\n`);
202
+ if (process.platform === 'win32') {
203
+ setTimeout(() => process.exit(1), 100);
204
+ }
205
+ else {
206
+ process.exit(1);
207
+ }
208
+ }
209
+ }
210
+ // Runtime config (shared, no side-effects)
211
+ const { useAuthBroker, isTestEnv, authBrokerPath, defaultMcpDestination, browser, unsafe, explicitTransportType, transportType, isHttp, isSse, isStdio, isEnvMandatory, envFilePath: initialEnvFilePath, } = (0, runtimeConfig_1.buildRuntimeConfig)();
212
+ // Skip .env autoload under explicit instructions, auth-broker, mcp default, or test env
213
+ const skipEnvAutoload = process.env.MCP_SKIP_ENV_LOAD === "true" ||
214
+ process.env.MCP_ENV_LOADED_BY_LAUNCHER === "true" ||
215
+ useAuthBroker ||
216
+ !!defaultMcpDestination ||
217
+ isTestEnv;
218
+ // If using auth-broker (--mcp or --auth-broker), clear SAP_* env vars to prevent .env from being used
219
+ // This ensures that even if .env was loaded earlier or vars are set in system, they won't be used
220
+ if (skipEnvAutoload && (useAuthBroker || !!defaultMcpDestination)) {
221
+ const sapEnvKeys = Object.keys(process.env).filter(key => key.startsWith('SAP_'));
222
+ for (const key of sapEnvKeys) {
223
+ delete process.env[key];
224
+ }
225
+ if (sapEnvKeys.length > 0 && !isStdio) {
226
+ process.stderr.write(`[MCP-ENV] Cleared ${sapEnvKeys.length} SAP_* environment variables (using auth-broker)\n`);
227
+ }
228
+ }
229
+ let envFilePath = initialEnvFilePath;
230
+ // Debug: Always log on Windows to help diagnose issues
231
+ if (process.platform === 'win32' && !isStdio) {
232
+ process.stderr.write(`[MCP-ENV] parseEnvArg() returned: ${envFilePath || '(undefined)'}\n`);
233
+ process.stderr.write(`[MCP-ENV] MCP_ENV_PATH: ${process.env.MCP_ENV_PATH || '(not set)'}\n`);
234
+ process.stderr.write(`[MCP-ENV] Final envFilePath: ${envFilePath || '(will search for .env)'}\n`);
235
+ }
236
+ if (!skipEnvAutoload) {
237
+ if (!envFilePath) {
238
+ // Default behavior: search in current working directory (where user runs the command)
239
+ // If .env exists, use it; otherwise will use auth-broker
240
+ const cwdEnvPath = path_1.default.resolve(process.cwd(), ".env");
241
+ if (fs_1.default.existsSync(cwdEnvPath)) {
242
+ envFilePath = cwdEnvPath;
243
+ // Only write to stderr if not in stdio mode (stdio mode requires clean JSON only)
244
+ if (!isStdio) {
245
+ process.stderr.write(`[MCP-ENV] Found .env file: ${envFilePath}\n`);
246
+ }
247
+ }
248
+ }
249
+ else {
250
+ // Only write to stderr if not in stdio mode
251
+ if (!isStdio) {
252
+ process.stderr.write(`[MCP-ENV] Using .env from argument/env: ${envFilePath}\n`);
253
+ // On Windows, also log the resolved path for debugging
254
+ if (process.platform === 'win32') {
255
+ const resolvedPath = path_1.default.isAbsolute(envFilePath)
256
+ ? envFilePath
257
+ : path_1.default.resolve(process.cwd(), envFilePath);
258
+ process.stderr.write(`[MCP-ENV] Will resolve to: ${resolvedPath}\n`);
259
+ }
260
+ }
261
+ }
262
+ if (envFilePath) {
263
+ // Normalize path separators for Windows compatibility
264
+ // On Windows, backslashes in paths need special handling
265
+ // path.resolve() and path.normalize() should handle this, but let's be explicit
266
+ // First, normalize all backslashes to forward slashes for consistent processing
267
+ // Then use path methods which handle platform-specific separators correctly
268
+ const normalizedPath = envFilePath.replace(/\\/g, '/');
269
+ if (!path_1.default.isAbsolute(normalizedPath)) {
270
+ // For relative paths, use path.resolve which handles .\ and ./ correctly on all platforms
271
+ // path.resolve automatically handles both .\mdd.env and ./mdd.env formats
272
+ envFilePath = path_1.default.resolve(process.cwd(), normalizedPath);
273
+ // Only write to stderr if not in stdio mode
274
+ if (!isStdio) {
275
+ process.stderr.write(`[MCP-ENV] Resolved relative path to: ${envFilePath}\n`);
276
+ }
277
+ }
278
+ else {
279
+ // For absolute paths, normalize using path.normalize
280
+ envFilePath = path_1.default.normalize(envFilePath);
281
+ }
282
+ // Verify file exists before attempting to load
283
+ if (!fs_1.default.existsSync(envFilePath)) {
284
+ const errorMsg = `[MCP-ENV] ✗ ERROR: .env file not found at: ${envFilePath}\n` +
285
+ `[MCP-ENV] Current working directory: ${process.cwd()}\n` +
286
+ `[MCP-ENV] Please check the path and try again.\n`;
287
+ process.stderr.write(errorMsg);
288
+ if (process.platform === 'win32') {
289
+ setTimeout(() => process.exit(1), 100);
290
+ }
291
+ else {
292
+ process.exit(1);
293
+ }
294
+ }
295
+ if (fs_1.default.existsSync(envFilePath)) {
296
+ // For stdio mode, load .env manually to avoid any output from dotenv library
297
+ if (isStdio) {
298
+ // Manual .env parsing for stdio mode (no library output)
299
+ try {
300
+ const envContent = fs_1.default.readFileSync(envFilePath, "utf8");
301
+ const lines = envContent.split(/\r?\n/);
302
+ for (const line of lines) {
303
+ const trimmed = line.trim();
304
+ // Skip empty lines and comments
305
+ if (!trimmed || trimmed.startsWith("#")) {
306
+ continue;
307
+ }
308
+ // Parse KEY=VALUE format
309
+ const eqIndex = trimmed.indexOf("=");
310
+ if (eqIndex === -1) {
311
+ continue;
312
+ }
313
+ const key = trimmed.substring(0, eqIndex).trim();
314
+ let value = trimmed.substring(eqIndex + 1);
315
+ // Remove inline comments (everything after #)
316
+ // This handles cases like: KEY=value # comment or KEY=value#comment
317
+ // Find first # and remove everything after it (including the #)
318
+ const commentIndex = value.indexOf('#');
319
+ if (commentIndex !== -1) {
320
+ // Remove everything from # onwards, then trim trailing whitespace
321
+ const beforeComment = value.substring(0, commentIndex);
322
+ value = beforeComment.trim();
323
+ }
324
+ else {
325
+ value = value.trim();
326
+ }
327
+ // Parse value: remove quotes and trim
328
+ let unquotedValue = value.trim();
329
+ unquotedValue = unquotedValue.replace(/^["']+|["']+$/g, '').trim();
330
+ // URLs from .env files are expected to be clean - just use as-is
331
+ if (key === 'SAP_URL') {
332
+ // No special processing needed
333
+ // Debug logging for Windows
334
+ if (process.platform === 'win32' && !isStdio) {
335
+ process.stderr.write(`[MCP-ENV] Parsed SAP_URL: "${unquotedValue}" (length: ${unquotedValue.length})\n`);
336
+ }
337
+ }
338
+ // Only set if not already in process.env (don't override launcher's cleaned values)
339
+ if (key && !process.env[key]) {
340
+ process.env[key] = unquotedValue;
341
+ }
342
+ }
343
+ }
344
+ catch (error) {
345
+ // Silent fail for stdio mode - just exit
346
+ process.exit(1);
347
+ }
348
+ }
349
+ else {
350
+ // For non-stdio modes, use manual parsing (dotenv removed to avoid stdout pollution)
351
+ try {
352
+ const envContent = fs_1.default.readFileSync(envFilePath, "utf8");
353
+ const lines = envContent.split(/\r?\n/);
354
+ for (const line of lines) {
355
+ const trimmed = line.trim();
356
+ if (!trimmed || trimmed.startsWith("#")) {
357
+ continue;
358
+ }
359
+ const eqIndex = trimmed.indexOf("=");
360
+ if (eqIndex === -1) {
361
+ continue;
362
+ }
363
+ const key = trimmed.substring(0, eqIndex).trim();
364
+ let value = trimmed.substring(eqIndex + 1);
365
+ // Remove inline comments (everything after #)
366
+ // This handles cases like: KEY=value # comment or KEY=value#comment
367
+ // Find first # and remove everything after it (including the #)
368
+ const commentIndex = value.indexOf('#');
369
+ if (commentIndex !== -1) {
370
+ // Remove everything from # onwards, then trim trailing whitespace
371
+ const beforeComment = value.substring(0, commentIndex);
372
+ value = beforeComment.trim();
373
+ }
374
+ else {
375
+ value = value.trim();
376
+ }
377
+ // Parse value: remove quotes and trim
378
+ let unquotedValue = value.trim();
379
+ unquotedValue = unquotedValue.replace(/^["']+|["']+$/g, '').trim();
380
+ // URLs from .env files are expected to be clean - just use as-is
381
+ if (key === 'SAP_URL') {
382
+ // No special processing needed
383
+ // Debug logging for Windows
384
+ if (process.platform === 'win32' && !isStdio) {
385
+ process.stderr.write(`[MCP-ENV] Parsed SAP_URL: "${unquotedValue}" (length: ${unquotedValue.length})\n`);
386
+ }
387
+ }
388
+ // Only set if not already in process.env (don't override launcher's cleaned values)
389
+ if (key && !process.env[key]) {
390
+ process.env[key] = unquotedValue;
391
+ }
392
+ }
393
+ process.stderr.write(`[MCP-ENV] ✓ Successfully loaded: ${envFilePath}\n`);
394
+ // Debug: log SAP_URL if loaded (for troubleshooting on Windows)
395
+ if (process.env.SAP_URL) {
396
+ const urlHex = Buffer.from(process.env.SAP_URL, 'utf8').toString('hex');
397
+ process.stderr.write(`[MCP-ENV] SAP_URL loaded: "${process.env.SAP_URL}" (length: ${process.env.SAP_URL.length})\n`);
398
+ if (process.platform === 'win32') {
399
+ process.stderr.write(`[MCP-ENV] SAP_URL (hex): ${urlHex.substring(0, 60)}...\n`);
400
+ // Check for comments
401
+ if (process.env.SAP_URL.includes('#')) {
402
+ process.stderr.write(`[MCP-ENV] ⚠ WARNING: SAP_URL contains # character (comment not removed?)\n`);
403
+ }
404
+ }
405
+ }
406
+ else {
407
+ process.stderr.write(`[MCP-ENV] ⚠ WARNING: SAP_URL not found in .env file\n`);
408
+ }
409
+ }
410
+ catch (error) {
411
+ process.stderr.write(`[MCP-ENV] ✗ Failed to load: ${envFilePath}\n`);
412
+ if (error instanceof Error) {
413
+ process.stderr.write(`[MCP-ENV] Error: ${error.message}\n`);
414
+ }
415
+ }
416
+ }
417
+ }
418
+ else {
419
+ // .env file specified but not found
420
+ if (isEnvMandatory) {
421
+ // Always write error to stderr (stderr is safe even in stdio mode, unlike stdout)
422
+ logger_1.logger?.error(".env file not found", { path: envFilePath });
423
+ process.stderr.write(`[MCP-ENV] ✗ ERROR: .env file not found at: ${envFilePath}\n`);
424
+ process.stderr.write(`[MCP-ENV] Current working directory: ${process.cwd()}\n`);
425
+ process.stderr.write(`[MCP-ENV] Transport mode '${transportType}' requires .env file.\n`);
426
+ process.stderr.write(`[MCP-ENV] Use --env=/path/to/.env to specify custom location\n`);
427
+ // On Windows, add a small delay before exit to allow error message to be visible
428
+ if (process.platform === 'win32') {
429
+ setTimeout(() => process.exit(1), 100);
430
+ }
431
+ else {
432
+ process.exit(1);
433
+ }
434
+ }
435
+ else {
436
+ // Always write error to stderr (stderr is safe even in stdio mode)
437
+ process.stderr.write(`[MCP-ENV] ✗ ERROR: .env file not found at: ${envFilePath}\n`);
438
+ process.stderr.write(`[MCP-ENV] Transport mode '${transportType}' was explicitly specified but .env file is missing.\n`);
439
+ process.stderr.write(`[MCP-ENV] Use --env=/path/to/.env to specify custom location\n`);
440
+ // On Windows, add a small delay before exit to allow error message to be visible
441
+ if (process.platform === 'win32') {
442
+ setTimeout(() => process.exit(1), 100);
443
+ }
444
+ else {
445
+ process.exit(1);
446
+ }
447
+ }
448
+ }
449
+ }
450
+ else {
451
+ // No .env file found and none specified
452
+ if (isEnvMandatory) {
453
+ // Transport explicitly set to stdio/sse but no .env found
454
+ const cwdEnvPath = path_1.default.resolve(process.cwd(), ".env");
455
+ // Always write error to stderr (stderr is safe even in stdio mode)
456
+ logger_1.logger?.error(".env file not found", { path: cwdEnvPath });
457
+ process.stderr.write(`[MCP-ENV] ✗ ERROR: .env file not found in current directory: ${process.cwd()}\n`);
458
+ process.stderr.write(`[MCP-ENV] Transport mode '${transportType}' requires .env file.\n`);
459
+ process.stderr.write(`[MCP-ENV] Use --env=/path/to/.env to specify custom location\n`);
460
+ // On Windows, add a small delay before exit to allow error message to be visible
461
+ if (process.platform === 'win32') {
462
+ setTimeout(() => process.exit(1), 100);
463
+ }
464
+ else {
465
+ process.exit(1);
466
+ }
467
+ }
468
+ else {
469
+ // No .env found, but transport is stdio (default) - this is OK for HTTP/SSE, but stdio requires .env or --mcp
470
+ if (explicitTransportType === null) {
471
+ // Transport not specified, using default (stdio)
472
+ // For stdio mode, don't write to stderr
473
+ if (!isStdio) {
474
+ process.stderr.write(`[MCP-ENV] NOTE: No .env file found in current directory: ${process.cwd()}\n`);
475
+ process.stderr.write(`[MCP-ENV] Starting in HTTP mode (no .env file required)\n`);
476
+ }
477
+ }
478
+ else {
479
+ // Transport explicitly set to HTTP - this is OK
480
+ // For stdio mode, don't write to stderr
481
+ if (!isStdio) {
482
+ process.stderr.write(`[MCP-ENV] NOTE: No .env file found, continuing in ${transportType} mode\n`);
483
+ }
484
+ }
485
+ }
486
+ }
487
+ }
488
+ else if (envFilePath) {
489
+ if (!path_1.default.isAbsolute(envFilePath)) {
490
+ envFilePath = path_1.default.resolve(process.cwd(), envFilePath);
491
+ }
492
+ // For stdio mode, don't write to stderr
493
+ if (!isStdio) {
494
+ process.stderr.write(`[MCP-ENV] Environment autoload skipped; using provided path reference: ${envFilePath}\n`);
495
+ }
496
+ }
497
+ else {
498
+ // For stdio mode, don't write to stderr
499
+ if (!isStdio) {
500
+ process.stderr.write(`[MCP-ENV] Environment autoload skipped (MCP_SKIP_ENV_LOAD=true).\n`);
501
+ }
502
+ }
503
+ // --- END ENV FILE LOADING LOGIC ---
504
+ // Debug: Log loaded SAP_URL and SAP_CLIENT using the MCP-compatible logger
505
+ // Skip logging in stdio mode (MCP protocol requires clean JSON only)
506
+ if (!isStdio) {
507
+ const envLogPath = envFilePath ?? "(skipped)";
508
+ logger_1.logger?.info("SAP configuration loaded", {
509
+ type: "CONFIG_INFO",
510
+ SAP_URL: process.env.SAP_URL,
511
+ SAP_CLIENT: process.env.SAP_CLIENT || "(not set)",
512
+ SAP_AUTH_TYPE: process.env.SAP_AUTH_TYPE || "(not set)",
513
+ SAP_JWT_TOKEN: process.env.SAP_JWT_TOKEN ? "[set]" : "(not set)",
514
+ ENV_PATH: envLogPath,
515
+ CWD: process.cwd(),
516
+ DIRNAME: __dirname,
517
+ TRANSPORT: transportType
518
+ });
519
+ }
520
+ function getArgValue(name) {
521
+ const args = process.argv;
522
+ for (let i = 0; i < args.length; i++) {
523
+ const arg = args[i];
524
+ if (arg.startsWith(`${name}=`)) {
525
+ return arg.slice(name.length + 1);
526
+ }
527
+ if (arg === name && i + 1 < args.length) {
528
+ return args[i + 1];
529
+ }
530
+ }
531
+ return undefined;
532
+ }
533
+ function hasFlag(name) {
534
+ return process.argv.includes(name);
535
+ }
536
+ function parseBoolean(value) {
537
+ if (!value) {
538
+ return false;
539
+ }
540
+ const normalized = value.trim().toLowerCase();
541
+ return normalized === "1" || normalized === "true" || normalized === "yes" || normalized === "on";
542
+ }
543
+ function resolvePortOption(argName, envName, defaultValue) {
544
+ const rawValue = getArgValue(argName) ?? process.env[envName];
545
+ if (!rawValue) {
546
+ return defaultValue;
547
+ }
548
+ const port = Number.parseInt(rawValue, 10);
549
+ if (!Number.isInteger(port) || port <= 0 || port > 65535) {
550
+ throw new Error(`Invalid port value for ${argName}: ${rawValue}`);
551
+ }
552
+ return port;
553
+ }
554
+ function resolveBooleanOption(argName, envName, defaultValue) {
555
+ const argValue = getArgValue(argName);
556
+ if (argValue !== undefined) {
557
+ return parseBoolean(argValue);
558
+ }
559
+ if (hasFlag(argName)) {
560
+ return true;
561
+ }
562
+ const envValue = process.env[envName];
563
+ if (envValue !== undefined) {
564
+ return parseBoolean(envValue);
565
+ }
566
+ return defaultValue;
567
+ }
568
+ function resolveListOption(argName, envName) {
569
+ const rawValue = getArgValue(argName) ?? process.env[envName];
570
+ if (!rawValue) {
571
+ return undefined;
572
+ }
573
+ const items = rawValue
574
+ .split(",")
575
+ .map((entry) => entry.trim())
576
+ .filter((entry) => entry.length > 0);
577
+ return items.length > 0 ? items : undefined;
578
+ }
579
+ function parseTransportConfig() {
580
+ // Use the transport type we already determined (handles explicit args, env vars, and defaults)
581
+ const normalized = transportType;
582
+ if (normalized &&
583
+ normalized !== "stdio" &&
584
+ normalized !== "http" &&
585
+ normalized !== "streamable-http" &&
586
+ normalized !== "server" &&
587
+ normalized !== "sse") {
588
+ throw new Error(`Unsupported transport: ${normalized}`);
589
+ }
590
+ const sseRequested = normalized === "sse" ||
591
+ hasFlag("--sse");
592
+ if (sseRequested) {
593
+ const port = resolvePortOption("--sse-port", "MCP_SSE_PORT", 3001);
594
+ // Default to localhost (127.0.0.1) for security - only accepts local connections
595
+ // Use 0.0.0.0 to accept connections from all interfaces (less secure)
596
+ const host = getArgValue("--sse-host") ?? process.env.MCP_SSE_HOST ?? "127.0.0.1";
597
+ const allowedOrigins = resolveListOption("--sse-allowed-origins", "MCP_SSE_ALLOWED_ORIGINS");
598
+ const allowedHosts = resolveListOption("--sse-allowed-hosts", "MCP_SSE_ALLOWED_HOSTS");
599
+ const enableDnsRebindingProtection = resolveBooleanOption("--sse-enable-dns-protection", "MCP_SSE_ENABLE_DNS_PROTECTION", false);
600
+ return {
601
+ type: "sse",
602
+ host,
603
+ port,
604
+ allowedOrigins,
605
+ allowedHosts,
606
+ enableDnsRebindingProtection,
607
+ };
608
+ }
609
+ const httpRequested = normalized === "http" ||
610
+ normalized === "streamable-http" ||
611
+ normalized === "server" ||
612
+ hasFlag("--http") ||
613
+ // Note: Default is stdio (set in runtimeConfig), so this only applies if explicitly requested
614
+ (!sseRequested && normalized !== "stdio");
615
+ if (httpRequested) {
616
+ const port = resolvePortOption("--http-port", "MCP_HTTP_PORT", 3000);
617
+ // Default to localhost (127.0.0.1) for security - only accepts local connections
618
+ // Use 0.0.0.0 to accept connections from all interfaces (less secure)
619
+ const host = getArgValue("--http-host") ?? process.env.MCP_HTTP_HOST ?? "127.0.0.1";
620
+ const enableJsonResponse = resolveBooleanOption("--http-json-response", "MCP_HTTP_ENABLE_JSON_RESPONSE", false);
621
+ const allowedOrigins = resolveListOption("--http-allowed-origins", "MCP_HTTP_ALLOWED_ORIGINS");
622
+ const allowedHosts = resolveListOption("--http-allowed-hosts", "MCP_HTTP_ALLOWED_HOSTS");
623
+ const enableDnsRebindingProtection = resolveBooleanOption("--http-enable-dns-protection", "MCP_HTTP_ENABLE_DNS_PROTECTION", false);
624
+ return {
625
+ type: "streamable-http",
626
+ host,
627
+ port,
628
+ enableJsonResponse,
629
+ allowedOrigins,
630
+ allowedHosts,
631
+ enableDnsRebindingProtection,
632
+ };
633
+ }
634
+ return { type: "stdio" };
635
+ }
636
+ function setAbapConnectionOverride(connection) {
637
+ (0, utils_1.setConnectionOverride)(connection);
638
+ }
639
+ /**
640
+ * Retrieves SAP configuration from environment variables.
641
+ * Reads configuration from process.env (caller is responsible for loading .env file if needed).
642
+ *
643
+ * @returns {SapConfig} The SAP configuration object.
644
+ * @throws {Error} If any required environment variable is missing.
645
+ */
646
+ // Helper function for Windows-compatible logging
647
+ // Only logs when DEBUG_CONNECTORS, DEBUG_TESTS, or DEBUG_ADT_TESTS is enabled
648
+ function debugLog(message) {
649
+ const debugEnabled = process.env.DEBUG_CONNECTORS === 'true' ||
650
+ process.env.DEBUG_TESTS === 'true' ||
651
+ process.env.DEBUG_ADT_TESTS === 'true';
652
+ if (!debugEnabled) {
653
+ return; // Suppress debug logs when not in debug mode
654
+ }
655
+ // Try stderr first
656
+ try {
657
+ process.stderr.write(message);
658
+ }
659
+ catch (e) {
660
+ // Fallback to console.error for Windows
661
+ console.error(message.trim());
662
+ }
663
+ // Also try to write to a debug file on Windows
664
+ if (process.platform === 'win32') {
665
+ try {
666
+ const fs = require('fs');
667
+ const path = require('path');
668
+ const debugFile = path.join(process.cwd(), 'mcp-debug.log');
669
+ fs.appendFileSync(debugFile, `${new Date().toISOString()} ${message}`, 'utf8');
670
+ }
671
+ catch (e) {
672
+ // Ignore file write errors
673
+ }
674
+ }
675
+ }
676
+ // Re-export header constants from interfaces package
677
+ __exportStar(require("@mcp-abap-adt/interfaces"), exports);
678
+ // Re-export handler exporter for external server integration
679
+ var index_js_1 = require("../../lib/handlers/index.js");
680
+ Object.defineProperty(exports, "HandlerExporter", { enumerable: true, get: function () { return index_js_1.HandlerExporter; } });
681
+ Object.defineProperty(exports, "createDefaultHandlerExporter", { enumerable: true, get: function () { return index_js_1.createDefaultHandlerExporter; } });
682
+ /**
683
+ * Server class for interacting with ABAP systems via ADT.
684
+ */
685
+ class mcp_abap_adt_server {
686
+ allowProcessExit;
687
+ registerSignalHandlers;
688
+ mcpServer; // MCP server for all transports
689
+ sapConfig; // SAP configuration
690
+ hasEnvFile; // Track if .env file was found at startup
691
+ transportConfig;
692
+ httpServer;
693
+ shuttingDown = false;
694
+ defaultMcpDestination; // Default MCP destination from --mcp parameter
695
+ defaultDestination; // Default destination (from --mcp or .env, used when client doesn't specify)
696
+ mcpHandlers;
697
+ exposition = ['readonly', 'high']; // Default exposition
698
+ // Client session tracking for StreamableHTTP (like the example)
699
+ streamableHttpSessions = new Map();
700
+ // Map sessionId -> client key (streamable HTTP) for quick lookups
701
+ streamableSessionIndex = new Map();
702
+ // AuthBroker factory for creating and managing AuthBroker instances
703
+ authBrokerFactory;
704
+ // Path to .env file (used to create SessionStore when --mcp is not specified)
705
+ envFilePath;
706
+ /**
707
+ * Initialize default broker on server startup (for stdio/SSE transports)
708
+ * Creates broker with default destination from --mcp parameter or .env file
709
+ */
710
+ /**
711
+ * Initialize default broker using unified AuthBrokerFactory logic
712
+ * Sets defaultDestination based on what broker was created
713
+ */
714
+ async initializeDefaultBroker() {
715
+ // Use unified AuthBrokerFactory logic to initialize default broker
716
+ await this.authBrokerFactory.initializeDefaultBroker();
717
+ // Get default broker to determine default destination
718
+ const defaultBroker = this.authBrokerFactory.getDefaultBroker();
719
+ console.error("[DEBUG v1] initializeDefaultBroker result:", {
720
+ hasBroker: !!defaultBroker,
721
+ defaultMcpDestination: this.defaultMcpDestination,
722
+ envFilePath: this.envFilePath,
723
+ });
724
+ if (defaultBroker) {
725
+ // If we have --mcp, use that as default destination
726
+ if (this.defaultMcpDestination) {
727
+ this.defaultDestination = this.defaultMcpDestination;
728
+ }
729
+ else {
730
+ // Otherwise use 'default' as destination name
731
+ this.defaultDestination = 'default';
732
+ }
733
+ logger_1.logger?.info("Default broker initialized", {
734
+ type: "DEFAULT_BROKER_INITIALIZED",
735
+ destination: this.defaultDestination,
736
+ transport: this.transportConfig.type,
737
+ });
738
+ }
739
+ else {
740
+ logger_1.logger?.debug("No default broker created (no conditions met)", {
741
+ type: "NO_DEFAULT_BROKER",
742
+ transport: this.transportConfig.type,
743
+ });
744
+ }
745
+ }
746
+ /**
747
+ * Get or create AuthBroker for a specific destination (lazy initialization)
748
+ * If destination is not specified, returns default broker
749
+ */
750
+ async getOrCreateAuthBroker(destination, clientKey) {
751
+ // clientKey is ignored in unified logic (one broker per destination)
752
+ return this.authBrokerFactory.getOrCreateAuthBroker(destination);
753
+ }
754
+ async applyAuthHeaders(headers, sessionId, clientKey) {
755
+ // Security: If server is listening on non-local interface (0.0.0.0), don't use default destination
756
+ // Client must provide all connection parameters in headers - server only proxies to ABAP
757
+ const isNonLocalInterface = this.isListeningOnNonLocalInterface();
758
+ if (isNonLocalInterface) {
759
+ // Non-local interface: use only what client provides in headers, no default destination
760
+ if (!headers || Object.keys(headers).length === 0) {
761
+ logger_1.logger?.info("No headers provided - server listening on non-local interface requires all headers from client", {
762
+ type: "NO_HEADERS_NON_LOCAL_INTERFACE",
763
+ sessionId: sessionId?.substring(0, 8),
764
+ hint: `Server is listening on 0.0.0.0 - client must provide all connection parameters in headers. Server will not use default destination for security.`,
765
+ });
766
+ return;
767
+ }
768
+ // Use headers as-is, no default destination
769
+ logger_1.logger?.debug("Non-local interface: using only client-provided headers", {
770
+ type: "NON_LOCAL_INTERFACE_HEADERS_ONLY",
771
+ sessionId: sessionId?.substring(0, 8),
772
+ });
773
+ }
774
+ else {
775
+ // Local interface (127.0.0.1): can use default destination if no headers
776
+ // If no headers but defaultDestination is set, use it
777
+ // Client values have priority (Q10), but if no headers at all, use default
778
+ if (!headers || Object.keys(headers).length === 0) {
779
+ if (this.defaultDestination) {
780
+ // Use default destination to get connection config from broker
781
+ const authBroker = await this.getOrCreateAuthBroker(this.defaultDestination, clientKey || sessionId);
782
+ if (authBroker) {
783
+ try {
784
+ const connConfig = await authBroker.getConnectionConfig(this.defaultDestination);
785
+ if (connConfig?.serviceUrl) {
786
+ // Check authType from connection config BEFORE calling getToken()
787
+ const isBasicAuth = connConfig.authType === 'basic' || (connConfig.username && connConfig.password);
788
+ if (isBasicAuth) {
789
+ // Basic auth for on-premise
790
+ if (connConfig.username && connConfig.password) {
791
+ this.processBasicAuthConfigUpdate(connConfig.serviceUrl, connConfig.username, connConfig.password, sessionId);
792
+ logger_1.logger?.info("No headers provided, using default destination with basic auth", {
793
+ type: "NO_HEADERS_DEFAULT_DESTINATION_BASIC_AUTH",
794
+ destination: this.defaultDestination,
795
+ sessionId: sessionId?.substring(0, 8),
796
+ });
797
+ }
798
+ }
799
+ else {
800
+ // JWT auth for cloud
801
+ const jwtToken = await authBroker.getToken(this.defaultDestination);
802
+ if (jwtToken) {
803
+ // Create headers object with default destination
804
+ headers = {
805
+ [interfaces_1.HEADER_MCP_DESTINATION]: this.defaultDestination,
806
+ [interfaces_1.HEADER_SAP_URL]: connConfig.serviceUrl,
807
+ [interfaces_1.HEADER_SAP_JWT_TOKEN]: jwtToken,
808
+ };
809
+ logger_1.logger?.info("No headers provided, using default destination", {
810
+ type: "NO_HEADERS_DEFAULT_DESTINATION_USED",
811
+ destination: this.defaultDestination,
812
+ sessionId: sessionId?.substring(0, 8),
813
+ });
814
+ }
815
+ }
816
+ }
817
+ }
818
+ catch (error) {
819
+ logger_1.logger?.warn("Failed to get connection config from default destination", {
820
+ type: "DEFAULT_DESTINATION_CONFIG_FAILED",
821
+ destination: this.defaultDestination,
822
+ sessionId: sessionId?.substring(0, 8),
823
+ error: error instanceof Error ? error.message : String(error),
824
+ });
825
+ }
826
+ }
827
+ }
828
+ // If still no headers after trying default destination, log and return
829
+ if (!headers || Object.keys(headers).length === 0) {
830
+ logger_1.logger?.info("No headers provided in request and no default destination available", {
831
+ type: "NO_HEADERS_PROVIDED",
832
+ sessionId: sessionId?.substring(0, 8),
833
+ hint: `Provide authentication headers (${interfaces_1.HEADER_SAP_DESTINATION_SERVICE}, ${interfaces_1.HEADER_SAP_URL}, ${interfaces_1.HEADER_SAP_AUTH_TYPE}, etc.) or use --mcp parameter or .env file`,
834
+ });
835
+ return;
836
+ }
837
+ }
838
+ // Apply default destination if not provided in headers (client values have priority)
839
+ // Only for local interface
840
+ if (this.defaultDestination && !headers[interfaces_1.HEADER_MCP_DESTINATION] && !headers['X-MCP-Destination']) {
841
+ headers[interfaces_1.HEADER_MCP_DESTINATION] = this.defaultDestination;
842
+ logger_1.logger?.info("Using default destination (client didn't specify)", {
843
+ type: "DEFAULT_DESTINATION_APPLIED",
844
+ destination: this.defaultDestination,
845
+ sessionId: sessionId?.substring(0, 8),
846
+ });
847
+ }
848
+ }
849
+ // Ensure headers is set for processing below
850
+ if (!headers) {
851
+ headers = {};
852
+ }
853
+ const headersWithDefault = { ...headers };
854
+ // Log which auth headers are present (for debugging)
855
+ // Check headers in both cases (Node.js normalizes to lowercase, but check both for safety)
856
+ const authHeaders = {
857
+ [interfaces_1.HEADER_SAP_DESTINATION_SERVICE]: headersWithDefault[interfaces_1.HEADER_SAP_DESTINATION_SERVICE] || headersWithDefault['X-SAP-Destination'],
858
+ [interfaces_1.HEADER_MCP_DESTINATION]: headersWithDefault[interfaces_1.HEADER_MCP_DESTINATION] || headersWithDefault['X-MCP-Destination'],
859
+ [interfaces_1.HEADER_SAP_URL]: (headersWithDefault[interfaces_1.HEADER_SAP_URL] || headersWithDefault['X-SAP-URL']) ? '[present]' : undefined,
860
+ [interfaces_1.HEADER_SAP_AUTH_TYPE]: headersWithDefault[interfaces_1.HEADER_SAP_AUTH_TYPE] || headersWithDefault['X-SAP-Auth-Type'],
861
+ [interfaces_1.HEADER_SAP_JWT_TOKEN]: (headersWithDefault[interfaces_1.HEADER_SAP_JWT_TOKEN] || headersWithDefault['X-SAP-JWT-Token']) ? '[present]' : undefined,
862
+ [interfaces_1.HEADER_SAP_LOGIN]: (headersWithDefault[interfaces_1.HEADER_SAP_LOGIN] || headersWithDefault['X-SAP-Login']) ? '[present]' : undefined,
863
+ };
864
+ logger_1.logger?.info("Processing authentication headers", {
865
+ type: "AUTH_HEADERS_PROCESSING",
866
+ headers: authHeaders,
867
+ platform: process.platform,
868
+ sessionId: sessionId?.substring(0, 8),
869
+ allHeaderKeys: Object.keys(headersWithDefault).filter(k => {
870
+ const lowerKey = k.toLowerCase();
871
+ return lowerKey.startsWith('x-sap') || lowerKey.startsWith('x-mcp');
872
+ }),
873
+ });
874
+ // Use header validator to validate and prioritize authentication methods
875
+ const validationResult = (0, header_validator_1.validateAuthHeaders)(headersWithDefault);
876
+ // Log warnings if any
877
+ if (validationResult.warnings.length > 0) {
878
+ logger_1.logger?.debug("Header validation warnings", {
879
+ type: "HEADER_VALIDATION_WARNINGS",
880
+ warnings: validationResult.warnings,
881
+ sessionId: sessionId?.substring(0, 8),
882
+ });
883
+ }
884
+ // If validation failed, log info (not error) and return
885
+ // This is not an error - user may be using .env file or base config
886
+ if (!validationResult.isValid || !validationResult.config) {
887
+ if (validationResult.errors.length > 0) {
888
+ logger_1.logger?.debug("Header validation failed - will use .env file or base config", {
889
+ type: "HEADER_VALIDATION_FAILED",
890
+ errors: validationResult.errors,
891
+ sessionId: sessionId?.substring(0, 8),
892
+ hint: "No valid headers found. Will use .env file or base config if available.",
893
+ });
894
+ }
895
+ else {
896
+ logger_1.logger?.debug("No valid authentication headers found - will use .env file or base config", {
897
+ type: "NO_VALID_AUTH_HEADERS",
898
+ sessionId: sessionId?.substring(0, 8),
899
+ hint: "No headers provided. Will use .env file or base config if available.",
900
+ });
901
+ }
902
+ return;
903
+ }
904
+ const config = validationResult.config;
905
+ // Process based on priority (highest to lowest)
906
+ switch (config.priority) {
907
+ case header_validator_1.AuthMethodPriority.SAP_DESTINATION: {
908
+ // Priority 4: x-sap-destination (uses AuthBroker, URL from destination)
909
+ if (!config.destination) {
910
+ logger_1.logger?.warn("SAP destination auth requires destination name", {
911
+ type: "SAP_DESTINATION_AUTH_MISSING",
912
+ destination: config.destination,
913
+ sessionId: sessionId?.substring(0, 8),
914
+ });
915
+ return;
916
+ }
917
+ // Get or create AuthBroker for this destination (lazy initialization)
918
+ const authBroker = await this.getOrCreateAuthBroker(config.destination, clientKey || sessionId);
919
+ if (!authBroker) {
920
+ const errorMessage = `Failed to initialize AuthBroker for destination "${config.destination}". Auth-broker is only available for HTTP/streamable-http transport.`;
921
+ logger_1.logger?.error(errorMessage, {
922
+ type: "AUTH_BROKER_NOT_INITIALIZED",
923
+ destination: config.destination,
924
+ sessionId: sessionId?.substring(0, 8),
925
+ transport: this.transportConfig.type,
926
+ });
927
+ return;
928
+ }
929
+ try {
930
+ // Get connection config from AuthBroker (loads from .env or service key)
931
+ // Note: destination name must exactly match service key filename (case-sensitive)
932
+ // Example: if file is "sk.json", destination must be "sk" (not "SK")
933
+ const connConfig = await authBroker.getConnectionConfig(config.destination);
934
+ if (!connConfig || !connConfig.serviceUrl) {
935
+ logger_1.logger?.error("Failed to get SAP URL from destination", {
936
+ type: "SAP_DESTINATION_URL_NOT_FOUND",
937
+ destination: config.destination,
938
+ sessionId: sessionId?.substring(0, 8),
939
+ hint: `Service key file "${config.destination}.json" not found or missing URL. Check file name matches destination exactly (case-sensitive).`,
940
+ });
941
+ return;
942
+ }
943
+ const sapUrl = connConfig.serviceUrl;
944
+ logger_1.logger?.info("SAP URL retrieved from destination", {
945
+ type: "SAP_URL_RETRIEVED",
946
+ destination: config.destination,
947
+ url: sapUrl,
948
+ sessionId: sessionId?.substring(0, 8),
949
+ });
950
+ // Check authType from connection config BEFORE calling getToken()
951
+ const isBasicAuth = connConfig.authType === 'basic' || (connConfig.username && connConfig.password);
952
+ if (isBasicAuth) {
953
+ // Basic auth for on-premise
954
+ if (connConfig.username && connConfig.password) {
955
+ this.processBasicAuthConfigUpdate(sapUrl, connConfig.username, connConfig.password, sessionId);
956
+ logger_1.logger?.info("Updated SAP configuration using SAP destination with basic auth", {
957
+ type: "SAP_CONFIG_UPDATED_SAP_DESTINATION_BASIC_AUTH",
958
+ destination: config.destination,
959
+ url: sapUrl,
960
+ sessionId: sessionId?.substring(0, 8),
961
+ });
962
+ }
963
+ else {
964
+ logger_1.logger?.error("Basic auth requires username and password", {
965
+ type: "BASIC_AUTH_MISSING_CREDENTIALS",
966
+ destination: config.destination,
967
+ sessionId: sessionId?.substring(0, 8),
968
+ });
969
+ }
970
+ }
971
+ else {
972
+ // JWT auth for cloud
973
+ // Get token from AuthBroker
974
+ const jwtToken = await authBroker.getToken(config.destination);
975
+ // Register AuthBroker in global registry for connection to use during token refresh
976
+ const { registerAuthBroker } = require('./lib/utils');
977
+ registerAuthBroker(config.destination, authBroker);
978
+ this.processJwtConfigUpdate(sapUrl, jwtToken, undefined, config.destination, sessionId);
979
+ logger_1.logger?.info("Updated SAP configuration using SAP destination (AuthBroker)", {
980
+ type: "SAP_CONFIG_UPDATED_SAP_DESTINATION",
981
+ destination: config.destination,
982
+ url: sapUrl,
983
+ sessionId: sessionId?.substring(0, 8),
984
+ });
985
+ }
986
+ }
987
+ catch (error) {
988
+ logger_1.logger?.error("Failed to get token from AuthBroker for SAP destination", {
989
+ type: "AUTH_BROKER_ERROR_SAP_DESTINATION",
990
+ destination: config.destination,
991
+ error: error instanceof Error ? error.message : String(error),
992
+ sessionId: sessionId?.substring(0, 8),
993
+ });
994
+ }
995
+ return;
996
+ }
997
+ case header_validator_1.AuthMethodPriority.MCP_DESTINATION: {
998
+ // Priority 3: x-mcp-destination (uses AuthBroker, URL from destination or x-sap-url header)
999
+ if (!config.destination) {
1000
+ logger_1.logger?.warn("MCP destination auth requires destination", {
1001
+ type: "MCP_DESTINATION_AUTH_MISSING",
1002
+ destination: config.destination,
1003
+ sessionId: sessionId?.substring(0, 8),
1004
+ });
1005
+ return;
1006
+ }
1007
+ // Get or create AuthBroker for this destination (lazy initialization)
1008
+ const authBroker = await this.getOrCreateAuthBroker(config.destination, clientKey || sessionId);
1009
+ if (!authBroker) {
1010
+ logger_1.logger?.error("Failed to initialize AuthBroker for MCP destination", {
1011
+ type: "AUTH_BROKER_NOT_INITIALIZED",
1012
+ destination: config.destination,
1013
+ sessionId: sessionId?.substring(0, 8),
1014
+ transport: this.transportConfig.type,
1015
+ });
1016
+ return;
1017
+ }
1018
+ try {
1019
+ // Get connection config from AuthBroker (loads from .env or service key)
1020
+ // If x-sap-url was provided in headers, it will be ignored (warning already issued by validator)
1021
+ // Note: destination name must exactly match service key filename (case-sensitive)
1022
+ const connConfig = await authBroker.getConnectionConfig(config.destination);
1023
+ if (!connConfig || !connConfig.serviceUrl) {
1024
+ logger_1.logger?.error("Failed to get SAP URL from destination", {
1025
+ type: "MCP_DESTINATION_URL_NOT_FOUND",
1026
+ destination: config.destination,
1027
+ sessionId: sessionId?.substring(0, 8),
1028
+ hint: `Service key file "${config.destination}.json" not found or missing URL. Check file name matches destination exactly (case-sensitive).`,
1029
+ });
1030
+ return;
1031
+ }
1032
+ const sapUrl = connConfig.serviceUrl;
1033
+ logger_1.logger?.info("SAP URL retrieved from destination", {
1034
+ type: "SAP_URL_RETRIEVED",
1035
+ destination: config.destination,
1036
+ url: sapUrl,
1037
+ sessionId: sessionId?.substring(0, 8),
1038
+ });
1039
+ // Check authType from connection config BEFORE calling getToken()
1040
+ const isBasicAuth = connConfig.authType === 'basic' || (connConfig.username && connConfig.password);
1041
+ if (isBasicAuth) {
1042
+ // Basic auth for on-premise
1043
+ if (connConfig.username && connConfig.password) {
1044
+ this.processBasicAuthConfigUpdate(sapUrl, connConfig.username, connConfig.password, sessionId);
1045
+ logger_1.logger?.info("Updated SAP configuration using MCP destination with basic auth", {
1046
+ type: "SAP_CONFIG_UPDATED_MCP_DESTINATION_BASIC_AUTH",
1047
+ destination: config.destination,
1048
+ url: sapUrl,
1049
+ sessionId: sessionId?.substring(0, 8),
1050
+ });
1051
+ }
1052
+ else {
1053
+ logger_1.logger?.error("Basic auth requires username and password", {
1054
+ type: "BASIC_AUTH_MISSING_CREDENTIALS",
1055
+ destination: config.destination,
1056
+ sessionId: sessionId?.substring(0, 8),
1057
+ });
1058
+ }
1059
+ }
1060
+ else {
1061
+ // JWT auth for cloud
1062
+ // Get token from AuthBroker
1063
+ const jwtToken = await authBroker.getToken(config.destination);
1064
+ // Register AuthBroker in global registry for connection to use during token refresh
1065
+ const { registerAuthBroker } = require('../../lib/utils.js');
1066
+ registerAuthBroker(config.destination, authBroker);
1067
+ this.processJwtConfigUpdate(sapUrl, jwtToken, undefined, config.destination, sessionId);
1068
+ logger_1.logger?.info("Updated SAP configuration using MCP destination (AuthBroker)", {
1069
+ type: "SAP_CONFIG_UPDATED_MCP_DESTINATION",
1070
+ destination: config.destination,
1071
+ url: sapUrl,
1072
+ sessionId: sessionId?.substring(0, 8),
1073
+ });
1074
+ }
1075
+ }
1076
+ catch (error) {
1077
+ logger_1.logger?.error("Failed to get token from AuthBroker for MCP destination", {
1078
+ type: "AUTH_BROKER_ERROR_MCP_DESTINATION",
1079
+ destination: config.destination,
1080
+ error: error instanceof Error ? error.message : String(error),
1081
+ sessionId: sessionId?.substring(0, 8),
1082
+ });
1083
+ }
1084
+ return;
1085
+ }
1086
+ case header_validator_1.AuthMethodPriority.DIRECT_JWT: {
1087
+ // Priority 2: x-sap-jwt-token (direct JWT token)
1088
+ if (!config.sapUrl || !config.jwtToken) {
1089
+ logger_1.logger?.warn("Direct JWT auth requires URL and token", {
1090
+ type: "DIRECT_JWT_AUTH_MISSING",
1091
+ sapUrl: config.sapUrl,
1092
+ hasToken: !!config.jwtToken,
1093
+ sessionId: sessionId?.substring(0, 8),
1094
+ });
1095
+ return;
1096
+ }
1097
+ this.processJwtConfigUpdate(config.sapUrl, config.jwtToken, config.refreshToken, sessionId);
1098
+ logger_1.logger?.info("Updated SAP configuration using direct JWT token", {
1099
+ type: "SAP_CONFIG_UPDATED_DIRECT_JWT",
1100
+ url: config.sapUrl,
1101
+ sessionId: sessionId?.substring(0, 8),
1102
+ });
1103
+ return;
1104
+ }
1105
+ case header_validator_1.AuthMethodPriority.BASIC: {
1106
+ // Priority 1: x-sap-login + x-sap-password (basic auth)
1107
+ if (!config.sapUrl || !config.username || !config.password) {
1108
+ logger_1.logger?.warn("Basic auth requires URL, username, and password", {
1109
+ type: "BASIC_AUTH_MISSING",
1110
+ sapUrl: config.sapUrl,
1111
+ hasUsername: !!config.username,
1112
+ hasPassword: !!config.password,
1113
+ sessionId: sessionId?.substring(0, 8),
1114
+ });
1115
+ return;
1116
+ }
1117
+ this.processBasicAuthConfigUpdate(config.sapUrl, config.username, config.password, sessionId);
1118
+ logger_1.logger?.info("Updated SAP configuration using basic auth", {
1119
+ type: "SAP_CONFIG_UPDATED_BASIC",
1120
+ url: config.sapUrl,
1121
+ sessionId: sessionId?.substring(0, 8),
1122
+ });
1123
+ return;
1124
+ }
1125
+ default: {
1126
+ logger_1.logger?.warn("Unknown authentication method priority", {
1127
+ type: "UNKNOWN_AUTH_PRIORITY",
1128
+ priority: config.priority,
1129
+ sessionId: sessionId?.substring(0, 8),
1130
+ });
1131
+ return;
1132
+ }
1133
+ }
1134
+ }
1135
+ processJwtConfigUpdate(sapUrl, jwtToken, refreshToken, destination, sessionId) {
1136
+ const sanitizeToken = (token) => token.length <= 10 ? token : `${token.substring(0, 6)}…${token.substring(token.length - 4)}`;
1137
+ // URL from auth-broker/service key is already clean and correct, no need to clean it
1138
+ // Only validate format
1139
+ let cleanedUrl = sapUrl.trim();
1140
+ // Ensure URL has protocol
1141
+ if (!/^https?:\/\//.test(cleanedUrl)) {
1142
+ logger_1.logger?.error("Invalid URL format in processJwtConfigUpdate", {
1143
+ type: "INVALID_URL_FORMAT",
1144
+ originalUrl: sapUrl,
1145
+ cleanedUrl: cleanedUrl,
1146
+ sessionId: sessionId?.substring(0, 8),
1147
+ });
1148
+ throw new Error(`Invalid URL format: "${sapUrl}". Expected format: https://your-system.sap.com`);
1149
+ }
1150
+ // Normalize URL using URL object
1151
+ try {
1152
+ const urlObj = new URL(cleanedUrl);
1153
+ cleanedUrl = urlObj.href.replace(/\/$/, ''); // Remove trailing slash
1154
+ }
1155
+ catch (urlError) {
1156
+ logger_1.logger?.error("Failed to parse URL in processJwtConfigUpdate", {
1157
+ type: "URL_PARSE_ERROR",
1158
+ url: cleanedUrl,
1159
+ error: urlError instanceof Error ? urlError.message : String(urlError),
1160
+ sessionId: sessionId?.substring(0, 8),
1161
+ });
1162
+ throw new Error(`Invalid URL: "${sapUrl}". Error: ${urlError instanceof Error ? urlError.message : urlError}`);
1163
+ }
1164
+ // Use cleaned URL
1165
+ sapUrl = cleanedUrl;
1166
+ let baseConfig = this.sapConfig;
1167
+ // Don't load from .env if using auth-broker (--mcp or --auth-broker)
1168
+ // This prevents .env from being used when destination-based auth is specified
1169
+ const isUsingAuthBroker = this.defaultMcpDestination || useAuthBroker;
1170
+ if ((!baseConfig || baseConfig.url === "http://placeholder") && !isUsingAuthBroker) {
1171
+ try {
1172
+ baseConfig = (0, config_js_1.getConfig)();
1173
+ }
1174
+ catch (error) {
1175
+ logger_1.logger?.warn("Failed to load base SAP config when applying headers", {
1176
+ type: "SAP_CONFIG_HEADER_APPLY_FAILED",
1177
+ error: error instanceof Error ? error.message : String(error),
1178
+ });
1179
+ baseConfig = {
1180
+ url: sapUrl,
1181
+ authType: "jwt",
1182
+ };
1183
+ }
1184
+ }
1185
+ else if (!baseConfig || baseConfig.url === "http://placeholder") {
1186
+ // Using auth-broker, don't load from .env
1187
+ baseConfig = {
1188
+ url: sapUrl,
1189
+ authType: "jwt",
1190
+ };
1191
+ }
1192
+ // Check if any configuration changed
1193
+ const urlChanged = sapUrl !== baseConfig.url;
1194
+ const authTypeChanged = "jwt" !== baseConfig.authType;
1195
+ const tokenChanged = baseConfig.jwtToken !== jwtToken ||
1196
+ (!!refreshToken && refreshToken.trim() !== baseConfig.refreshToken);
1197
+ if (!urlChanged && !authTypeChanged && !tokenChanged) {
1198
+ return;
1199
+ }
1200
+ const newConfig = {
1201
+ ...baseConfig,
1202
+ url: sapUrl,
1203
+ authType: "jwt",
1204
+ jwtToken,
1205
+ };
1206
+ if (refreshToken && refreshToken.trim()) {
1207
+ newConfig.refreshToken = refreshToken.trim();
1208
+ }
1209
+ (0, config_js_1.setSapConfigOverride)(newConfig);
1210
+ this.sapConfig = newConfig;
1211
+ // Store config and destination in session if sessionId is provided
1212
+ if (sessionId) {
1213
+ const clientKeyForSession = this.streamableSessionIndex.get(sessionId);
1214
+ const session = clientKeyForSession ? this.streamableHttpSessions.get(clientKeyForSession) : undefined;
1215
+ if (session) {
1216
+ session.sapConfig = newConfig;
1217
+ if (destination) {
1218
+ session.destination = destination;
1219
+ }
1220
+ }
1221
+ }
1222
+ // Force connection cache invalidation (for backward compatibility)
1223
+ const { invalidateConnectionCache } = require('../../lib/utils.js');
1224
+ try {
1225
+ invalidateConnectionCache();
1226
+ }
1227
+ catch (error) {
1228
+ logger_1.logger?.debug("Connection cache invalidation failed", {
1229
+ type: "CONNECTION_CACHE_INVALIDATION_FAILED",
1230
+ error: error instanceof Error ? error.message : String(error),
1231
+ });
1232
+ }
1233
+ logger_1.logger?.info("Updated SAP configuration from HTTP headers (JWT)", {
1234
+ type: "SAP_CONFIG_UPDATED",
1235
+ urlChanged: Boolean(urlChanged),
1236
+ authTypeChanged: Boolean(authTypeChanged),
1237
+ tokenChanged: Boolean(tokenChanged),
1238
+ hasRefreshToken: Boolean(refreshToken),
1239
+ jwtPreview: sanitizeToken(jwtToken),
1240
+ sessionId: sessionId?.substring(0, 8),
1241
+ });
1242
+ }
1243
+ /**
1244
+ * Process JWT config update using AuthBroker for destination-based authentication
1245
+ * @private
1246
+ */
1247
+ async processJwtConfigUpdateWithAuthBroker(sapUrl, destination, sessionId) {
1248
+ // Get or create AuthBroker for this destination (lazy initialization)
1249
+ const authBroker = await this.getOrCreateAuthBroker(destination, sessionId);
1250
+ if (!authBroker) {
1251
+ logger_1.logger?.warn("AuthBroker not available, falling back to direct token", {
1252
+ type: "AUTH_BROKER_NOT_AVAILABLE",
1253
+ destination,
1254
+ transport: this.transportConfig.type,
1255
+ });
1256
+ return;
1257
+ }
1258
+ try {
1259
+ // Get token from AuthBroker (will load from .env, validate, and refresh if needed)
1260
+ const jwtToken = await authBroker.getToken(destination);
1261
+ // Load refresh token from .env if available (AuthBroker doesn't return it, but we can load it)
1262
+ // For now, we'll just use the access token - refresh will be handled by AuthBroker automatically
1263
+ const refreshToken = undefined; // AuthBroker handles refresh internally
1264
+ // Process JWT config update with the token from AuthBroker
1265
+ this.processJwtConfigUpdate(sapUrl, jwtToken, refreshToken, destination, sessionId);
1266
+ logger_1.logger?.info("Updated SAP configuration using AuthBroker (destination-based)", {
1267
+ type: "SAP_CONFIG_UPDATED_AUTH_BROKER",
1268
+ destination,
1269
+ url: sapUrl,
1270
+ sessionId: sessionId?.substring(0, 8),
1271
+ });
1272
+ }
1273
+ catch (error) {
1274
+ logger_1.logger?.error("Failed to get token from AuthBroker", {
1275
+ type: "AUTH_BROKER_ERROR",
1276
+ destination,
1277
+ error: error instanceof Error ? error.message : String(error),
1278
+ });
1279
+ // Don't throw - let the request continue with existing config or fail later
1280
+ }
1281
+ }
1282
+ processBasicAuthConfigUpdate(sapUrl, username, password, sessionId) {
1283
+ let baseConfig = this.sapConfig;
1284
+ if (!baseConfig || baseConfig.url === "http://placeholder") {
1285
+ try {
1286
+ baseConfig = (0, config_js_1.getConfig)();
1287
+ }
1288
+ catch (error) {
1289
+ logger_1.logger?.warn("Failed to load base SAP config when applying headers", {
1290
+ type: "SAP_CONFIG_HEADER_APPLY_FAILED",
1291
+ error: error instanceof Error ? error.message : String(error),
1292
+ });
1293
+ baseConfig = {
1294
+ url: sapUrl,
1295
+ authType: "basic",
1296
+ };
1297
+ }
1298
+ }
1299
+ // Check if any configuration changed
1300
+ const urlChanged = sapUrl !== baseConfig.url;
1301
+ const authTypeChanged = "basic" !== baseConfig.authType;
1302
+ const credentialsChanged = baseConfig.username !== username ||
1303
+ baseConfig.password !== password;
1304
+ if (!urlChanged && !authTypeChanged && !credentialsChanged) {
1305
+ return;
1306
+ }
1307
+ const newConfig = {
1308
+ ...baseConfig,
1309
+ url: sapUrl,
1310
+ authType: "basic",
1311
+ username,
1312
+ password,
1313
+ };
1314
+ (0, config_js_1.setSapConfigOverride)(newConfig);
1315
+ this.sapConfig = newConfig;
1316
+ // Store config in session if sessionId is provided
1317
+ if (sessionId) {
1318
+ const clientKeyForSession = this.streamableSessionIndex.get(sessionId);
1319
+ const session = clientKeyForSession ? this.streamableHttpSessions.get(clientKeyForSession) : undefined;
1320
+ if (session) {
1321
+ session.sapConfig = newConfig;
1322
+ }
1323
+ }
1324
+ // Force connection cache invalidation (for backward compatibility)
1325
+ const { invalidateConnectionCache } = require('../../lib/utils.js');
1326
+ try {
1327
+ invalidateConnectionCache();
1328
+ }
1329
+ catch (error) {
1330
+ logger_1.logger?.debug("Connection cache invalidation failed", {
1331
+ type: "CONNECTION_CACHE_INVALIDATION_FAILED",
1332
+ error: error instanceof Error ? error.message : String(error),
1333
+ });
1334
+ }
1335
+ logger_1.logger?.info("Updated SAP configuration from HTTP headers (Basic)", {
1336
+ type: "SAP_CONFIG_UPDATED",
1337
+ urlChanged: Boolean(urlChanged),
1338
+ authTypeChanged: Boolean(authTypeChanged),
1339
+ credentialsChanged: Boolean(credentialsChanged),
1340
+ hasUsername: Boolean(username),
1341
+ sessionId: sessionId?.substring(0, 8),
1342
+ });
1343
+ }
1344
+ /**
1345
+ * Check if connection is from localhost
1346
+ */
1347
+ isLocalConnection(remoteAddress) {
1348
+ if (!remoteAddress) {
1349
+ return false;
1350
+ }
1351
+ // Check for IPv4 localhost
1352
+ if (remoteAddress === "127.0.0.1" || remoteAddress === "localhost") {
1353
+ return true;
1354
+ }
1355
+ // Check for IPv6 localhost
1356
+ if (remoteAddress === "::1" || remoteAddress === "::ffff:127.0.0.1") {
1357
+ return true;
1358
+ }
1359
+ // Check if it's a loopback interface
1360
+ if (remoteAddress.startsWith("127.") || remoteAddress.startsWith("::1")) {
1361
+ return true;
1362
+ }
1363
+ return false;
1364
+ }
1365
+ /**
1366
+ * Check if server is listening on non-local interface (0.0.0.0)
1367
+ * When listening on 0.0.0.0, we don't use default destination - client must provide all headers
1368
+ */
1369
+ isListeningOnNonLocalInterface() {
1370
+ if (this.transportConfig.type === "streamable-http" || this.transportConfig.type === "sse") {
1371
+ const host = this.transportConfig.host;
1372
+ // If host is 0.0.0.0, ::, or empty, it accepts connections from all interfaces
1373
+ return host === "0.0.0.0" || host === "::" || host === "" || !host;
1374
+ }
1375
+ // stdio is always local
1376
+ return false;
1377
+ }
1378
+ /**
1379
+ * Check if request has SAP connection headers
1380
+ */
1381
+ hasSapHeaders(headers) {
1382
+ if (!headers) {
1383
+ return false;
1384
+ }
1385
+ // Check for destination-based auth headers
1386
+ if (headers[interfaces_1.HEADER_SAP_DESTINATION_SERVICE] || headers[interfaces_1.HEADER_MCP_DESTINATION]) {
1387
+ return true;
1388
+ }
1389
+ // Check for direct auth headers
1390
+ const sapUrl = headers[interfaces_1.HEADER_SAP_URL];
1391
+ const sapAuthType = headers[interfaces_1.HEADER_SAP_AUTH_TYPE];
1392
+ return !!(sapUrl && sapAuthType);
1393
+ }
1394
+ /**
1395
+ * Constructor for the mcp_abap_adt_server class.
1396
+ */
1397
+ constructor(options) {
1398
+ this.allowProcessExit = options?.allowProcessExit ?? true;
1399
+ this.registerSignalHandlers = options?.registerSignalHandlers ?? true;
1400
+ this.defaultMcpDestination = defaultMcpDestination;
1401
+ this.envFilePath = envFilePath; // Store .env file path for SessionStore creation
1402
+ // Parse exposition from CLI args or use default
1403
+ if (options?.exposition) {
1404
+ this.exposition = options.exposition;
1405
+ }
1406
+ else {
1407
+ // Parse --exposition from CLI
1408
+ const expositionArg = process.argv.find(arg => arg.startsWith('--exposition='));
1409
+ if (expositionArg) {
1410
+ const sets = expositionArg.split('=')[1]?.split(',').map(s => s.trim()).filter(Boolean) || [];
1411
+ this.exposition = sets.length > 0 ? sets : ['readonly', 'high'];
1412
+ }
1413
+ }
1414
+ // Initialize AuthBroker factory
1415
+ const brokerConfig = new AuthBrokerConfig_js_1.AuthBrokerConfig(this.defaultMcpDestination, this.defaultDestination, this.envFilePath, authBrokerPath, unsafe, transportType, useAuthBroker, browser, logger_1.logger);
1416
+ this.authBrokerFactory = new index_1.AuthBrokerFactory(brokerConfig);
1417
+ this.mcpHandlers = new mcp_handlers_1.McpHandlers();
1418
+ // Check if .env file exists (was loaded at startup)
1419
+ // This is used to determine if we should restrict non-local connections
1420
+ this.hasEnvFile = fs_1.default.existsSync(envFilePath || path_1.default.resolve(process.cwd(), ".env"));
1421
+ if (options?.connection) {
1422
+ setAbapConnectionOverride(options.connection);
1423
+ }
1424
+ else {
1425
+ setAbapConnectionOverride(undefined);
1426
+ }
1427
+ if (!options?.connection) {
1428
+ (0, config_js_1.setSapConfigOverride)(options?.sapConfig);
1429
+ }
1430
+ // CHANGED: Don't validate config in constructor - will validate on actual ABAP requests
1431
+ // This allows creating server instance without .env file when using runtime config (e.g., from HTTP headers)
1432
+ try {
1433
+ if (options?.sapConfig) {
1434
+ this.sapConfig = options.sapConfig;
1435
+ }
1436
+ else if (!options?.connection) {
1437
+ // Don't load .env config if using auth-broker (--mcp or --auth-broker)
1438
+ // Connection will be created via auth-broker instead
1439
+ if (this.defaultMcpDestination || useAuthBroker) {
1440
+ // Using auth-broker, don't load .env config
1441
+ this.sapConfig = {
1442
+ url: "http://placeholder",
1443
+ authType: "basic",
1444
+ };
1445
+ logger_1.logger?.debug("Skipping .env config load (using auth-broker)", {
1446
+ type: "SKIP_ENV_CONFIG_FOR_AUTH_BROKER",
1447
+ defaultMcpDestination: this.defaultMcpDestination,
1448
+ useAuthBroker,
1449
+ });
1450
+ }
1451
+ else {
1452
+ // Try to get config from .env, but don't fail if it's invalid - server should still initialize
1453
+ // Invalid config will be caught when handlers try to use it
1454
+ try {
1455
+ this.sapConfig = (0, config_js_1.getConfig)();
1456
+ }
1457
+ catch (configError) {
1458
+ // For stdio mode, we want the server to initialize even with invalid config
1459
+ // The error will be shown when user tries to use a tool
1460
+ // Check stdio mode using environment variable or stdin check (transportConfig not set yet)
1461
+ const isStdioMode = process.env.MCP_TRANSPORT === "stdio" || !process.stdin.isTTY;
1462
+ if (isStdioMode) {
1463
+ // In stdio mode, write error to stderr (safe for MCP protocol)
1464
+ process.stderr.write(`[MCP] ⚠ WARNING: Invalid SAP configuration: ${configError instanceof Error ? configError.message : String(configError)}\n`);
1465
+ process.stderr.write(`[MCP] Server will start, but tools will fail until configuration is fixed.\n`);
1466
+ }
1467
+ logger_1.logger?.warn("SAP config invalid at initialization, will use placeholder", {
1468
+ type: "CONFIG_INVALID",
1469
+ error: configError instanceof Error ? configError.message : String(configError),
1470
+ });
1471
+ // Set a placeholder that will be replaced when valid config is provided
1472
+ this.sapConfig = { url: "http://placeholder", authType: "jwt", jwtToken: "placeholder" };
1473
+ }
1474
+ }
1475
+ }
1476
+ else {
1477
+ this.sapConfig = { url: "http://injected-connection", authType: "jwt", jwtToken: "injected" };
1478
+ }
1479
+ }
1480
+ catch (error) {
1481
+ // If config is not available yet, that's OK - it will be provided later via setSapConfigOverride or DI
1482
+ logger_1.logger?.warn("SAP config not available at initialization, will use runtime config", {
1483
+ type: "CONFIG_DEFERRED",
1484
+ error: error instanceof Error ? error.message : String(error),
1485
+ });
1486
+ // Set a placeholder that will be replaced
1487
+ this.sapConfig = { url: "http://placeholder", authType: "jwt", jwtToken: "placeholder" };
1488
+ }
1489
+ try {
1490
+ this.transportConfig = options?.transportConfig ?? parseTransportConfig();
1491
+ }
1492
+ catch (error) {
1493
+ const message = error instanceof Error ? error.message : String(error);
1494
+ // Always write error to stderr (stderr is safe even in stdio mode)
1495
+ logger_1.logger?.error("Failed to parse transport configuration", {
1496
+ type: "TRANSPORT_CONFIG_ERROR",
1497
+ error: message,
1498
+ });
1499
+ process.stderr.write(`[MCP] ✗ ERROR: Failed to parse transport configuration: ${message}\n`);
1500
+ if (this.allowProcessExit) {
1501
+ // On Windows, add a small delay before exit to allow error message to be visible
1502
+ if (process.platform === 'win32') {
1503
+ setTimeout(() => process.exit(1), 100);
1504
+ }
1505
+ else {
1506
+ process.exit(1);
1507
+ }
1508
+ }
1509
+ throw error instanceof Error ? error : new Error(message);
1510
+ }
1511
+ // Create McpServer (for all transports)
1512
+ this.mcpServer = new mcp_js_1.McpServer({
1513
+ name: "mcp-abap-adt",
1514
+ version: "0.1.0"
1515
+ });
1516
+ // AuthBroker will be initialized lazily when needed (per destination)
1517
+ // Only for HTTP/streamable-http transport (not for stdio or SSE)
1518
+ const isHttpTransport = this.transportConfig.type === "streamable-http";
1519
+ if (isHttpTransport && !useAuthBroker) {
1520
+ // Only initialize if --auth-broker flag is NOT set (for stdio/SSE, ignore the flag)
1521
+ // For stdio/SSE, --auth-broker flag is ignored
1522
+ }
1523
+ else if (isHttpTransport && useAuthBroker) {
1524
+ // Support DEBUG_AUTH_BROKER as alias for DEBUG_AUTH_LOG
1525
+ // If DEBUG_AUTH_BROKER is set, ensure DEBUG_AUTH_LOG is also set for auth-broker package
1526
+ if (process.env.DEBUG_AUTH_BROKER === "true" && !process.env.DEBUG_AUTH_LOG) {
1527
+ process.env.DEBUG_AUTH_LOG = "true";
1528
+ }
1529
+ // Get paths for service keys and sessions
1530
+ // Use authBrokerPath if provided, otherwise use default platform paths
1531
+ // If authBrokerPath is provided, it's the base path - service-keys and sessions will be subdirectories
1532
+ const customPath = authBrokerPath ? path_1.default.resolve(authBrokerPath.replace(/^~/, os.homedir())) : undefined;
1533
+ const serviceKeysPaths = (0, platformPaths_1.getPlatformPaths)(customPath, 'service-keys');
1534
+ const sessionsPaths = (0, platformPaths_1.getPlatformPaths)(customPath, 'sessions');
1535
+ // Create directories if they don't exist
1536
+ const fs = require('fs');
1537
+ const serviceKeysDir = serviceKeysPaths[0]; // First path is where we save
1538
+ const sessionsDir = sessionsPaths[0]; // First path is where we save
1539
+ if (!fs.existsSync(serviceKeysDir)) {
1540
+ fs.mkdirSync(serviceKeysDir, { recursive: true });
1541
+ logger_1.logger?.info("Created service keys directory", {
1542
+ type: "SERVICE_KEYS_DIR_CREATED",
1543
+ path: serviceKeysDir,
1544
+ });
1545
+ }
1546
+ if (!fs.existsSync(sessionsDir)) {
1547
+ fs.mkdirSync(sessionsDir, { recursive: true });
1548
+ logger_1.logger?.info("Created sessions directory", {
1549
+ type: "SESSIONS_DIR_CREATED",
1550
+ path: sessionsDir,
1551
+ });
1552
+ }
1553
+ logger_1.logger?.info("AuthBroker will be initialized lazily when destination is needed", {
1554
+ type: "AUTH_BROKER_LAZY_INIT",
1555
+ transport: this.transportConfig.type,
1556
+ useAuthBrokerFlag: useAuthBroker,
1557
+ hasEnvFile: !!envFilePath,
1558
+ authBrokerPath: customPath || 'default',
1559
+ });
1560
+ // Print paths information with stars and empty lines
1561
+ console.log('');
1562
+ console.log('********************************************************************************');
1563
+ console.log('* AuthBroker Storage Paths:');
1564
+ console.log('*');
1565
+ console.log('* Service Keys (searched in order):');
1566
+ serviceKeysPaths.forEach((p, i) => {
1567
+ console.log(`* ${i + 1}. ${p}`);
1568
+ });
1569
+ console.log('*');
1570
+ console.log('* Sessions (saved to):');
1571
+ sessionsPaths.forEach((p, i) => {
1572
+ console.log(`* ${i + 1}. ${p}`);
1573
+ });
1574
+ console.log('********************************************************************************');
1575
+ console.log('');
1576
+ }
1577
+ else {
1578
+ logger_1.logger?.info("AuthBroker not available - not needed for this transport type", {
1579
+ type: "AUTH_BROKER_SKIPPED",
1580
+ transport: this.transportConfig.type,
1581
+ reason: "AuthBroker is only used for HTTP/streamable-http transport. For stdio/SSE, use .env file instead.",
1582
+ });
1583
+ }
1584
+ if (this.transportConfig.type === "streamable-http") {
1585
+ logger_1.logger?.info("Transport configured", {
1586
+ type: "TRANSPORT_CONFIG",
1587
+ transport: this.transportConfig.type,
1588
+ host: this.transportConfig.host,
1589
+ port: this.transportConfig.port,
1590
+ enableJsonResponse: this.transportConfig.enableJsonResponse,
1591
+ allowedOrigins: this.transportConfig.allowedOrigins ?? [],
1592
+ allowedHosts: this.transportConfig.allowedHosts ?? [],
1593
+ enableDnsRebindingProtection: this.transportConfig.enableDnsRebindingProtection,
1594
+ });
1595
+ }
1596
+ else if (this.transportConfig.type === "sse") {
1597
+ logger_1.logger?.info("Transport configured", {
1598
+ type: "TRANSPORT_CONFIG",
1599
+ transport: this.transportConfig.type,
1600
+ host: this.transportConfig.host,
1601
+ port: this.transportConfig.port,
1602
+ allowedOrigins: this.transportConfig.allowedOrigins ?? [],
1603
+ allowedHosts: this.transportConfig.allowedHosts ?? [],
1604
+ enableDnsRebindingProtection: this.transportConfig.enableDnsRebindingProtection,
1605
+ });
1606
+ }
1607
+ else {
1608
+ logger_1.logger?.info("Transport configured", {
1609
+ type: "TRANSPORT_CONFIG",
1610
+ transport: this.transportConfig.type,
1611
+ });
1612
+ }
1613
+ // Register handlers immediately if context is provided (for embedding scenarios)
1614
+ if (options?.context) {
1615
+ this.registerHandlers(options.context);
1616
+ logger_1.logger?.info("Handlers registered via context injection", {
1617
+ type: "HANDLERS_REGISTERED_VIA_CONTEXT",
1618
+ exposition: this.exposition,
1619
+ });
1620
+ }
1621
+ }
1622
+ /**
1623
+ * Creates AbapConnection from available sources (headers, broker, or .env)
1624
+ * @param headers - Optional HTTP headers containing connection info
1625
+ * @param sessionId - Optional session ID
1626
+ * @param destination - Optional destination name for broker-based auth
1627
+ * @returns AbapConnection instance
1628
+ * @private
1629
+ */
1630
+ async getOrCreateConnectionForServer(headers, sessionId, destination) {
1631
+ // Extract destination from headers if not provided
1632
+ let actualDestination = destination;
1633
+ if (!actualDestination && headers) {
1634
+ actualDestination = headers[interfaces_1.HEADER_MCP_DESTINATION] ||
1635
+ headers['X-MCP-Destination'] ||
1636
+ headers['x-mcp-destination'];
1637
+ }
1638
+ // Use default destination if still not set
1639
+ if (!actualDestination && this.defaultDestination) {
1640
+ actualDestination = this.defaultDestination;
1641
+ logger_1.logger?.debug('Using default destination for connection', {
1642
+ destination: actualDestination,
1643
+ type: 'DEFAULT_DESTINATION_USED',
1644
+ });
1645
+ }
1646
+ logger_1.logger?.info("Creating connection for server", {
1647
+ type: "CONNECTION_CREATION_START",
1648
+ hasHeaders: !!headers,
1649
+ sessionId: sessionId || 'not-provided',
1650
+ destination: actualDestination || 'not-provided',
1651
+ });
1652
+ // Try to get connection from session context first
1653
+ const context = utils_1.sessionContext.getStore();
1654
+ if (context?.sapConfig) {
1655
+ logger_1.logger?.info("Using connection from session context", {
1656
+ type: "CONNECTION_FROM_SESSION_CONTEXT",
1657
+ sessionId: sessionId || 'not-provided',
1658
+ url: context.sapConfig.url,
1659
+ authType: context.sapConfig.authType,
1660
+ });
1661
+ const sessionConnection = (0, connection_1.createAbapConnection)(context.sapConfig, loggerAdapter_1.loggerAdapter, sessionId || `mcp-server-${(0, crypto_1.randomUUID)()}`);
1662
+ return sessionConnection;
1663
+ }
1664
+ // If headers provided, create connection from headers
1665
+ if (headers && this.hasSapHeaders(headers)) {
1666
+ // Get config from headers (already processed by applyAuthHeaders)
1667
+ const config = this.sapConfig;
1668
+ if (config && config.url !== "http://placeholder" && config.url !== "http://injected-connection") {
1669
+ // If destination is known, try to refresh token via auth broker before creating connection
1670
+ if (actualDestination) {
1671
+ try {
1672
+ const brokerForHeaders = await this.getOrCreateAuthBroker(actualDestination, sessionId || 'global');
1673
+ if (brokerForHeaders) {
1674
+ const freshToken = await brokerForHeaders.getToken(actualDestination);
1675
+ if (freshToken && config) {
1676
+ config.authorizationToken = freshToken;
1677
+ }
1678
+ const { registerAuthBroker } = require('../../lib/utils.js');
1679
+ registerAuthBroker(actualDestination, brokerForHeaders);
1680
+ }
1681
+ }
1682
+ catch (e) {
1683
+ logger_1.logger?.warn?.("Auth broker refresh failed for header connection", {
1684
+ type: "CONNECTION_FROM_HEADERS_BROKER_WARN",
1685
+ error: e instanceof Error ? e.message : String(e),
1686
+ });
1687
+ }
1688
+ }
1689
+ logger_1.logger?.info("Using connection from headers", {
1690
+ type: "CONNECTION_FROM_HEADERS",
1691
+ sessionId: sessionId || 'not-provided',
1692
+ url: config.url,
1693
+ authType: config.authType,
1694
+ });
1695
+ let connection = (0, connection_1.createAbapConnection)(config, loggerAdapter_1.loggerAdapter, sessionId || `mcp-server-${(0, crypto_1.randomUUID)()}`);
1696
+ return connection;
1697
+ }
1698
+ }
1699
+ // If destination provided, create connection via broker
1700
+ if (actualDestination) {
1701
+ try {
1702
+ logger_1.logger?.info("Attempting to create connection via auth broker", {
1703
+ type: "CONNECTION_VIA_BROKER_ATTEMPT",
1704
+ destination: actualDestination,
1705
+ sessionId: sessionId || 'not-provided',
1706
+ });
1707
+ const authBroker = await this.getOrCreateAuthBroker(actualDestination, sessionId || 'global');
1708
+ console.error("[DEBUG v1] authBroker result:", { hasBroker: !!authBroker, destination: actualDestination });
1709
+ if (authBroker) {
1710
+ const connConfig = await authBroker.getConnectionConfig(actualDestination);
1711
+ console.error("[DEBUG v1] connConfig result:", {
1712
+ hasConfig: !!connConfig,
1713
+ serviceUrl: connConfig?.serviceUrl?.substring(0, 50),
1714
+ authType: connConfig?.authType,
1715
+ hasToken: !!connConfig?.authorizationToken,
1716
+ hasUsername: !!connConfig?.username,
1717
+ });
1718
+ if (connConfig?.serviceUrl) {
1719
+ // Register AuthBroker in global registry for connection to use during token refresh
1720
+ const { registerAuthBroker } = require('../../lib/utils.js');
1721
+ registerAuthBroker(actualDestination, authBroker);
1722
+ // Determine auth type from connection config (like v2)
1723
+ const authType = connConfig.authType ||
1724
+ (connConfig.username && connConfig.password ? 'basic' : 'jwt');
1725
+ let config;
1726
+ if (authType === 'basic') {
1727
+ // Basic auth - use username/password from connection config
1728
+ config = {
1729
+ url: connConfig.serviceUrl,
1730
+ authType: "basic",
1731
+ username: connConfig.username,
1732
+ password: connConfig.password,
1733
+ client: connConfig.sapClient,
1734
+ };
1735
+ logger_1.logger?.info("Using basic auth connection from auth broker", {
1736
+ type: "CONNECTION_FROM_BROKER_BASIC",
1737
+ destination: actualDestination,
1738
+ sessionId: sessionId || 'not-provided',
1739
+ url: config.url,
1740
+ authType: config.authType,
1741
+ });
1742
+ }
1743
+ else {
1744
+ // JWT auth - try to get fresh token from broker
1745
+ let jwtToken;
1746
+ try {
1747
+ jwtToken = await authBroker.getToken(actualDestination);
1748
+ }
1749
+ catch (error) {
1750
+ // Broker can't provide/refresh token (e.g., no UAA credentials for .env-only setup)
1751
+ // Use existing token from connectionConfig
1752
+ logger_1.logger?.debug?.("Broker can't refresh token, using existing token from session", {
1753
+ type: "TOKEN_REFRESH_FALLBACK",
1754
+ destination: actualDestination,
1755
+ error: error instanceof Error ? error.message : String(error),
1756
+ });
1757
+ jwtToken = connConfig.authorizationToken;
1758
+ }
1759
+ const tokenToUse = jwtToken || connConfig.authorizationToken;
1760
+ if (!tokenToUse) {
1761
+ logger_1.logger?.warn("No JWT token available for connection", {
1762
+ type: "NO_JWT_TOKEN",
1763
+ destination: actualDestination,
1764
+ });
1765
+ throw new Error(`No JWT token available for destination: ${actualDestination}`);
1766
+ }
1767
+ config = {
1768
+ url: connConfig.serviceUrl,
1769
+ authType: "jwt",
1770
+ jwtToken: tokenToUse,
1771
+ client: connConfig.sapClient,
1772
+ };
1773
+ logger_1.logger?.info("Using JWT auth connection from auth broker", {
1774
+ type: "CONNECTION_FROM_BROKER_JWT",
1775
+ destination: actualDestination,
1776
+ sessionId: sessionId || 'not-provided',
1777
+ url: config.url,
1778
+ authType: config.authType,
1779
+ });
1780
+ }
1781
+ // Create connection
1782
+ let connection = (0, connection_1.createAbapConnection)(config, loggerAdapter_1.loggerAdapter, sessionId || `mcp-server-${(0, crypto_1.randomUUID)()}`);
1783
+ return connection;
1784
+ }
1785
+ }
1786
+ }
1787
+ catch (error) {
1788
+ logger_1.logger?.warn("Failed to create connection from destination", {
1789
+ type: "CONNECTION_FROM_DESTINATION_FAILED",
1790
+ destination: actualDestination,
1791
+ error: error instanceof Error ? error.message : String(error),
1792
+ });
1793
+ }
1794
+ }
1795
+ // Fallback to default config (from .env or constructor)
1796
+ // BUT: Don't use .env fallback if we have defaultDestination (means we're using auth-broker)
1797
+ // This prevents .env from being used when --mcp is specified
1798
+ if (this.sapConfig &&
1799
+ this.sapConfig.url !== "http://placeholder" &&
1800
+ this.sapConfig.url !== "http://injected-connection" &&
1801
+ !this.defaultDestination) { // Don't fallback to .env if using auth-broker
1802
+ logger_1.logger?.info("Using connection from default config (.env or constructor)", {
1803
+ type: "CONNECTION_FROM_DEFAULT_CONFIG",
1804
+ sessionId: sessionId || 'not-provided',
1805
+ url: this.sapConfig.url,
1806
+ authType: this.sapConfig.authType,
1807
+ });
1808
+ return (0, connection_1.createAbapConnection)(this.sapConfig, loggerAdapter_1.loggerAdapter, sessionId || `mcp-server-${(0, crypto_1.randomUUID)()}`);
1809
+ }
1810
+ logger_1.logger?.error("Unable to create connection: no valid configuration available", {
1811
+ type: "CONNECTION_CREATION_FAILED",
1812
+ hasHeaders: !!headers,
1813
+ sessionId: sessionId || 'not-provided',
1814
+ destination: actualDestination || 'not-provided',
1815
+ defaultDestination: this.defaultDestination || 'not-set',
1816
+ hasSapConfig: !!this.sapConfig,
1817
+ sapConfigUrl: this.sapConfig?.url || 'not-set',
1818
+ });
1819
+ throw new Error("Unable to create connection: no valid configuration available");
1820
+ }
1821
+ /**
1822
+ * Creates a new McpServer instance with all handlers registered
1823
+ * Used for SSE sessions where each session needs its own server instance
1824
+ * @param context - HandlerContext instance to use for handlers
1825
+ * @private
1826
+ */
1827
+ createMcpServerForSession(context) {
1828
+ const server = new mcp_js_1.McpServer({
1829
+ name: "mcp-abap-adt",
1830
+ version: "0.1.0"
1831
+ });
1832
+ // Register all tools using McpHandlers
1833
+ const handlers = new mcp_handlers_1.McpHandlers();
1834
+ handlers.RegisterAllToolsOnServer(server, context, this.exposition);
1835
+ return server;
1836
+ }
1837
+ /**
1838
+ * Register handlers on the internal McpServer with a provided context.
1839
+ * Use this when embedding mcp_abap_adt_server in an external server
1840
+ * that manages its own connection lifecycle.
1841
+ *
1842
+ * @param context - HandlerContext with connection and logger
1843
+ * @public
1844
+ */
1845
+ registerHandlers(context) {
1846
+ this.mcpHandlers.RegisterAllToolsOnServer(this.mcpServer, context, this.exposition);
1847
+ }
1848
+ /**
1849
+ * Sets up handlers for new McpServer using registerTool (recommended API)
1850
+ * @param context - HandlerContext with connection and logger
1851
+ * @private
1852
+ */
1853
+ setupMcpServerHandlers(context) {
1854
+ // Connection is already wrapped with token refresh in run() method
1855
+ // Just register handlers with the provided context
1856
+ this.mcpHandlers.RegisterAllToolsOnServer(this.mcpServer, context, this.exposition);
1857
+ }
1858
+ /**
1859
+ * Creates a wrapper connection that refreshes token before each request
1860
+ * @private
1861
+ */
1862
+ createConnectionWithTokenRefresh(connection, destination) {
1863
+ const connectionWithRefresh = connection;
1864
+ // Wrap makeAdtRequest to refresh token before each request
1865
+ if (connectionWithRefresh.makeAdtRequest) {
1866
+ const originalMakeAdtRequest = connectionWithRefresh.makeAdtRequest.bind(connection);
1867
+ connectionWithRefresh.makeAdtRequest = async function (options) {
1868
+ // Always refresh token via AuthBroker before request (AuthBroker will refresh if needed)
1869
+ const { getAuthBroker } = require('../../lib/utils.js');
1870
+ const authBroker = getAuthBroker(destination);
1871
+ logger_1.logger?.debug('makeAdtRequest called, checking AuthBroker', {
1872
+ destination,
1873
+ hasAuthBroker: !!authBroker,
1874
+ method: options?.method,
1875
+ url: options?.url,
1876
+ });
1877
+ if (!authBroker) {
1878
+ logger_1.logger?.warn('AuthBroker not found for destination, cannot refresh token', {
1879
+ destination,
1880
+ type: 'AUTH_BROKER_NOT_FOUND',
1881
+ });
1882
+ // Continue without refresh - will use existing token
1883
+ return await originalMakeAdtRequest(options);
1884
+ }
1885
+ try {
1886
+ // Get fresh token from AuthBroker (will refresh automatically if expired)
1887
+ logger_1.logger?.debug('Requesting fresh token from AuthBroker', {
1888
+ destination,
1889
+ type: 'TOKEN_REFRESH_REQUEST',
1890
+ });
1891
+ const freshToken = await authBroker.getToken(destination);
1892
+ const config = connectionWithRefresh.getConfig();
1893
+ if (config) {
1894
+ // Always update token (AuthBroker.getToken() returns fresh token)
1895
+ const tokenChanged = config.jwtToken !== freshToken;
1896
+ const oldToken = config.jwtToken;
1897
+ logger_1.logger?.debug('Updating connection config with fresh token', {
1898
+ destination,
1899
+ tokenChanged,
1900
+ oldTokenPreview: oldToken ? oldToken.substring(0, 20) + '...' : 'none',
1901
+ newTokenPreview: freshToken.substring(0, 20) + '...',
1902
+ type: 'TOKEN_UPDATE',
1903
+ });
1904
+ config.jwtToken = freshToken;
1905
+ // Verify token was updated
1906
+ const verifyConfig = connectionWithRefresh.getConfig();
1907
+ if (verifyConfig.jwtToken !== freshToken) {
1908
+ logger_1.logger?.error('Token update failed - config.jwtToken does not match fresh token', {
1909
+ destination,
1910
+ expectedPreview: freshToken.substring(0, 20) + '...',
1911
+ actualPreview: verifyConfig.jwtToken ? verifyConfig.jwtToken.substring(0, 20) + '...' : 'none',
1912
+ type: 'TOKEN_UPDATE_FAILED',
1913
+ });
1914
+ }
1915
+ // Get refresh token from session store if available
1916
+ try {
1917
+ const { authorizationConfig } = await authBroker.getConnectionConfig(destination);
1918
+ if (authorizationConfig?.refreshToken) {
1919
+ config.refreshToken = authorizationConfig.refreshToken;
1920
+ }
1921
+ }
1922
+ catch (configError) {
1923
+ // Ignore errors getting refresh token (not critical)
1924
+ logger_1.logger?.debug('Could not get refresh token from AuthBroker', {
1925
+ destination,
1926
+ error: configError instanceof Error ? configError.message : String(configError),
1927
+ });
1928
+ }
1929
+ // Reset connection only if token changed to ensure fresh token is used
1930
+ // This ensures that buildAuthorizationHeader() will use the new token
1931
+ // Don't reset if token didn't change to preserve CSRF token and cookies
1932
+ if (tokenChanged) {
1933
+ connectionWithRefresh.reset();
1934
+ logger_1.logger?.info('Token refreshed via AuthBroker before request', {
1935
+ destination,
1936
+ tokenPreview: freshToken.substring(0, 20) + '...',
1937
+ oldTokenPreview: oldToken ? oldToken.substring(0, 20) + '...' : 'none',
1938
+ type: 'TOKEN_REFRESHED_BEFORE_REQUEST',
1939
+ });
1940
+ }
1941
+ else {
1942
+ // Token didn't change - no need to reset, connection can reuse CSRF token and cookies
1943
+ logger_1.logger?.debug('Token verified via AuthBroker before request (no change, keeping session)', {
1944
+ destination,
1945
+ tokenPreview: freshToken.substring(0, 20) + '...',
1946
+ type: 'TOKEN_VERIFIED_BEFORE_REQUEST',
1947
+ });
1948
+ }
1949
+ }
1950
+ else {
1951
+ logger_1.logger?.warn('Connection config not available, cannot update token', {
1952
+ destination,
1953
+ type: 'CONNECTION_CONFIG_NOT_AVAILABLE',
1954
+ });
1955
+ }
1956
+ }
1957
+ catch (error) {
1958
+ logger_1.logger?.error('Failed to refresh token before request', {
1959
+ error: error instanceof Error ? error.message : String(error),
1960
+ destination,
1961
+ errorStack: error instanceof Error ? error.stack : undefined,
1962
+ type: 'TOKEN_REFRESH_FAILED',
1963
+ });
1964
+ // Continue with existing token - will try to use it, but may fail if expired
1965
+ }
1966
+ // Call original makeAdtRequest (with potentially refreshed token)
1967
+ try {
1968
+ return await originalMakeAdtRequest(options);
1969
+ }
1970
+ catch (error) {
1971
+ // If we still get 401/403 or "JWT token has expired" error, try to refresh token again
1972
+ const isAuthError = error?.response?.status === 401 || error?.response?.status === 403;
1973
+ const isExpiredTokenError = error?.message?.includes('JWT token has expired') ||
1974
+ error?.message?.includes('Please re-authenticate');
1975
+ if ((isAuthError || isExpiredTokenError) && authBroker) {
1976
+ // Check if this is a permissions error, not an auth error
1977
+ const responseData = error?.response?.data;
1978
+ const responseText = typeof responseData === "string" ? responseData : JSON.stringify(responseData || "");
1979
+ if (responseText.includes("ExceptionResourceNoAccess") ||
1980
+ responseText.includes("No authorization") ||
1981
+ responseText.includes("Missing authorization")) {
1982
+ // Not an auth token issue, re-throw
1983
+ throw error;
1984
+ }
1985
+ // Try to refresh token again and retry
1986
+ try {
1987
+ logger_1.logger?.info('Got 401/403 after token refresh, attempting to refresh token again', {
1988
+ destination,
1989
+ error: error?.message,
1990
+ type: 'TOKEN_REFRESH_RETRY',
1991
+ });
1992
+ const freshToken = await authBroker.getToken(destination);
1993
+ const config = connectionWithRefresh.getConfig();
1994
+ if (config) {
1995
+ config.jwtToken = freshToken;
1996
+ // Get refresh token from session store if available
1997
+ try {
1998
+ const { authorizationConfig } = await authBroker.getConnectionConfig(destination);
1999
+ if (authorizationConfig?.refreshToken) {
2000
+ config.refreshToken = authorizationConfig.refreshToken;
2001
+ }
2002
+ }
2003
+ catch (configError) {
2004
+ // Ignore errors getting refresh token
2005
+ }
2006
+ // Reset connection to use new token
2007
+ connectionWithRefresh.reset();
2008
+ logger_1.logger?.info('Token refreshed again, retrying request', {
2009
+ destination,
2010
+ tokenPreview: freshToken.substring(0, 20) + '...',
2011
+ type: 'TOKEN_REFRESHED_RETRY',
2012
+ });
2013
+ // Retry the request with new token
2014
+ return await originalMakeAdtRequest(options);
2015
+ }
2016
+ }
2017
+ catch (refreshError) {
2018
+ logger_1.logger?.error('Failed to refresh token on retry', {
2019
+ destination,
2020
+ error: refreshError instanceof Error ? refreshError.message : String(refreshError),
2021
+ type: 'TOKEN_REFRESH_RETRY_FAILED',
2022
+ });
2023
+ // Re-throw original error if refresh fails
2024
+ throw error;
2025
+ }
2026
+ }
2027
+ // Re-throw error if not handled
2028
+ throw error;
2029
+ }
2030
+ };
2031
+ }
2032
+ return connectionWithRefresh;
2033
+ }
2034
+ setupSignalHandlers() {
2035
+ const signals = ["SIGINT", "SIGTERM"];
2036
+ for (const signal of signals) {
2037
+ process.on(signal, () => {
2038
+ if (this.shuttingDown) {
2039
+ return;
2040
+ }
2041
+ this.shuttingDown = true;
2042
+ logger_1.logger?.info("Received shutdown signal", {
2043
+ type: "SERVER_SHUTDOWN_SIGNAL",
2044
+ signal,
2045
+ transport: this.transportConfig.type,
2046
+ });
2047
+ void this.shutdown().finally(() => {
2048
+ if (this.allowProcessExit) {
2049
+ process.exit(0);
2050
+ }
2051
+ });
2052
+ });
2053
+ }
2054
+ }
2055
+ async shutdown() {
2056
+ try {
2057
+ await this.mcpServer.close();
2058
+ }
2059
+ catch (error) {
2060
+ logger_1.logger?.error("Failed to close MCP server", {
2061
+ type: "SERVER_SHUTDOWN_ERROR",
2062
+ error: error instanceof Error ? error.message : String(error),
2063
+ });
2064
+ }
2065
+ if (this.httpServer) {
2066
+ await new Promise((resolve) => {
2067
+ this.httpServer?.close((closeError) => {
2068
+ if (closeError) {
2069
+ logger_1.logger?.error("Failed to close HTTP server", {
2070
+ type: "HTTP_SERVER_SHUTDOWN_ERROR",
2071
+ error: closeError instanceof Error ? closeError.message : String(closeError),
2072
+ });
2073
+ }
2074
+ resolve();
2075
+ });
2076
+ });
2077
+ this.httpServer = undefined;
2078
+ }
2079
+ }
2080
+ }
2081
+ exports.mcp_abap_adt_server = mcp_abap_adt_server;
2082
+ // if (process.env.MCP_SKIP_AUTO_START !== "true") {
2083
+ // const server = new mcp_abap_adt_server();
2084
+ // server.run().catch((error) => {
2085
+ // logger?.error("Fatal error while running MCP server", {
2086
+ // type: "SERVER_FATAL_ERROR",
2087
+ // error: error instanceof Error ? error.message : String(error),
2088
+ // });
2089
+ // // Always write to stderr (safe even in stdio mode)
2090
+ // process.stderr.write(`[MCP] ✗ Fatal error: ${error instanceof Error ? error.message : String(error)}\n`);
2091
+ // // On Windows, add a small delay before exit to allow error message to be visible
2092
+ // if (process.platform === 'win32') {
2093
+ // setTimeout(() => process.exit(1), 100);
2094
+ // } else {
2095
+ // process.exit(1);
2096
+ // }
2097
+ // });
2098
+ // }
2099
+ //# sourceMappingURL=legacy-server.js.map