@loop_ouroboros/mcp-hub-lite 1.0.2 → 1.1.0

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 (333) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/dist/client/assets/{HomeView-7rMg9C6t.js → HomeView-Bu2joUvW.js} +1 -1
  3. package/dist/client/assets/ResourceDetailView-BvrhDCD1.js +1 -0
  4. package/dist/client/assets/ResourceDetailView-DUJZbegl.css +1 -0
  5. package/dist/client/assets/ResourcesView-Cc8RHtia.css +1 -0
  6. package/dist/client/assets/ResourcesView-LjqioF_s.js +1 -0
  7. package/dist/client/assets/ServerDashboard-BfLeFDGw.css +1 -0
  8. package/dist/client/assets/ServerDashboard-FhHJFvUi.js +1 -0
  9. package/dist/client/assets/ServerDetail-BKV-M4qT.js +2 -0
  10. package/dist/client/assets/ServerDetail-CtnNKJGx.css +1 -0
  11. package/dist/client/assets/{ServerListView-Bws09jNR.css → ServerListView-B-bPljsO.css} +1 -1
  12. package/dist/client/assets/ServerListView-BXgtDyt3.js +36 -0
  13. package/dist/client/assets/ServerStatusTags.vue_vue_type_script_setup_true_lang-D-ooYNdN.js +1 -0
  14. package/dist/client/assets/SettingsView-CMFG91Z4.js +1 -0
  15. package/dist/client/assets/SettingsView-GkBOKL0V.css +1 -0
  16. package/dist/client/assets/ToolCallDialog-Bf4Xe4gH.js +1 -0
  17. package/dist/client/assets/ToolsView-DFpha1z0.js +1 -0
  18. package/dist/client/assets/{_baseClone-5q1b0P3O.js → _baseClone-Bp9Rjwd7.js} +1 -1
  19. package/dist/client/assets/el-form-item-B4LbJ6OO.css +1 -0
  20. package/dist/client/assets/el-form-item-DdSUWYsl.js +12 -0
  21. package/dist/client/assets/el-input-99gMrutP.js +1 -0
  22. package/dist/client/assets/el-input-BH4BZKnG.css +1 -0
  23. package/dist/client/assets/{el-loading-H85n3BUC.js → el-loading-CIQ5pD5u.js} +1 -1
  24. package/dist/client/assets/el-overlay-BVM6msGX.js +1 -0
  25. package/dist/client/assets/{el-select-C0U_l4IZ.css → el-overlay-CBvdpA69.css} +1 -1
  26. package/dist/client/assets/{ResourceDetailView-BdOaL_-o.css → el-radio-group-B0bauIRR.css} +1 -1
  27. package/dist/client/assets/el-radio-group-DhXWy7ry.js +1 -0
  28. package/dist/client/assets/el-skeleton-item-BLY1jEuR.css +1 -0
  29. package/dist/client/assets/el-skeleton-item-DJz-Us12.js +1 -0
  30. package/dist/client/assets/el-switch-BBrS-_6y.css +1 -0
  31. package/dist/client/assets/el-switch-Bu8AQ5uM.js +1 -0
  32. package/dist/client/assets/el-tab-pane-BnGMaV56.js +1 -0
  33. package/dist/client/assets/el-table-column-BMWOaLS_.js +1 -0
  34. package/dist/client/assets/el-table-column-BdvRS9Y2.css +1 -0
  35. package/dist/client/assets/index-C2V-ZGji.js +1 -0
  36. package/dist/client/assets/{index-BsDWtoIl.css → index-DpH6ZSbs.css} +1 -1
  37. package/dist/client/assets/index-vhkqgpmN.js +2 -0
  38. package/dist/client/assets/{omit-DPsOVNIJ.js → omit-CqPQN3XP.js} +1 -1
  39. package/dist/client/assets/{raf-DY5mgbuB.js → raf-C2wXzaVU.js} +1 -1
  40. package/dist/client/assets/{vue-vendor-6ny5zj9i.js → vue-vendor-BLHLXXJK.js} +1 -1
  41. package/dist/client/index.html +3 -3
  42. package/dist/server/shared/models/resource.model.d.ts +2 -1
  43. package/dist/server/shared/models/resource.model.d.ts.map +1 -1
  44. package/dist/server/shared/models/server.model.d.ts +362 -5
  45. package/dist/server/shared/models/server.model.d.ts.map +1 -1
  46. package/dist/server/shared/models/server.model.js +220 -1
  47. package/dist/server/shared/models/session.model.d.ts +1 -57
  48. package/dist/server/shared/models/session.model.d.ts.map +1 -1
  49. package/dist/server/shared/models/session.model.js +1 -55
  50. package/dist/server/shared/models/tool.model.d.ts +4 -2
  51. package/dist/server/shared/models/tool.model.d.ts.map +1 -1
  52. package/dist/server/shared/types/session-context.types.d.ts +0 -2
  53. package/dist/server/shared/types/session-context.types.d.ts.map +1 -1
  54. package/dist/server/shared/types/websocket.types.d.ts +17 -10
  55. package/dist/server/shared/types/websocket.types.d.ts.map +1 -1
  56. package/dist/server/src/api/mcp/gateway.d.ts +1 -3
  57. package/dist/server/src/api/mcp/gateway.d.ts.map +1 -1
  58. package/dist/server/src/api/mcp/gateway.js +19 -50
  59. package/dist/server/src/api/mcp/session-context-extractor.d.ts.map +1 -1
  60. package/dist/server/src/api/mcp/session-context-extractor.js +5 -14
  61. package/dist/server/src/api/web/hub-tools.d.ts +2 -2
  62. package/dist/server/src/api/web/hub-tools.d.ts.map +1 -1
  63. package/dist/server/src/api/web/hub-tools.js +3 -54
  64. package/dist/server/src/api/web/mcp-status.d.ts +1 -1
  65. package/dist/server/src/api/web/mcp-status.d.ts.map +1 -1
  66. package/dist/server/src/api/web/mcp-status.js +71 -30
  67. package/dist/server/src/api/web/resources.d.ts.map +1 -1
  68. package/dist/server/src/api/web/resources.js +28 -22
  69. package/dist/server/src/api/web/search.d.ts +2 -16
  70. package/dist/server/src/api/web/search.d.ts.map +1 -1
  71. package/dist/server/src/api/web/search.js +24 -45
  72. package/dist/server/src/api/web/servers.d.ts +3 -3
  73. package/dist/server/src/api/web/servers.d.ts.map +1 -1
  74. package/dist/server/src/api/web/servers.js +70 -25
  75. package/dist/server/src/api/ws/ws-handler.d.ts.map +1 -1
  76. package/dist/server/src/api/ws/ws-handler.js +4 -2
  77. package/dist/server/src/app.d.ts.map +1 -1
  78. package/dist/server/src/app.js +0 -2
  79. package/dist/server/src/cli/commands/list.js +2 -2
  80. package/dist/server/src/cli/commands/status.d.ts.map +1 -1
  81. package/dist/server/src/cli/commands/status.js +41 -30
  82. package/dist/server/src/cli/index.d.ts.map +1 -1
  83. package/dist/server/src/cli/index.js +2 -1
  84. package/dist/server/src/cli/server.d.ts +11 -2
  85. package/dist/server/src/cli/server.d.ts.map +1 -1
  86. package/dist/server/src/config/config-change-logger.d.ts +22 -0
  87. package/dist/server/src/config/config-change-logger.d.ts.map +1 -1
  88. package/dist/server/src/config/config-change-logger.js +135 -11
  89. package/dist/server/src/config/config-loader.d.ts +6 -5
  90. package/dist/server/src/config/config-loader.d.ts.map +1 -1
  91. package/dist/server/src/config/config-loader.js +54 -16
  92. package/dist/server/src/config/config-manager.d.ts +51 -43
  93. package/dist/server/src/config/config-manager.d.ts.map +1 -1
  94. package/dist/server/src/config/config-manager.js +84 -66
  95. package/dist/server/src/config/config-migrator.d.ts +82 -0
  96. package/dist/server/src/config/config-migrator.d.ts.map +1 -0
  97. package/dist/server/src/config/config-migrator.js +348 -0
  98. package/dist/server/src/config/config-saver.d.ts +2 -0
  99. package/dist/server/src/config/config-saver.d.ts.map +1 -1
  100. package/dist/server/src/config/config-saver.js +8 -2
  101. package/dist/server/src/config/config.schema.d.ts +10 -104
  102. package/dist/server/src/config/config.schema.d.ts.map +1 -1
  103. package/dist/server/src/config/config.schema.js +15 -99
  104. package/dist/server/src/config/path-validator.d.ts +27 -0
  105. package/dist/server/src/config/path-validator.d.ts.map +1 -0
  106. package/dist/server/src/config/path-validator.js +53 -0
  107. package/dist/server/src/config/server-config-manager.d.ts +37 -31
  108. package/dist/server/src/config/server-config-manager.d.ts.map +1 -1
  109. package/dist/server/src/config/server-config-manager.js +222 -66
  110. package/dist/server/src/config/type-converter.d.ts.map +1 -1
  111. package/dist/server/src/config/type-converter.js +3 -2
  112. package/dist/server/src/models/event.model.d.ts +17 -10
  113. package/dist/server/src/models/event.model.d.ts.map +1 -1
  114. package/dist/server/src/models/server.model.d.ts +17 -3
  115. package/dist/server/src/models/server.model.d.ts.map +1 -1
  116. package/dist/server/src/models/server.model.js +2 -1
  117. package/dist/server/src/models/system-tools.constants.d.ts +10 -27
  118. package/dist/server/src/models/system-tools.constants.d.ts.map +1 -1
  119. package/dist/server/src/models/system-tools.constants.js +4 -8
  120. package/dist/server/src/pid/manager.d.ts.map +1 -1
  121. package/dist/server/src/pid/manager.js +2 -1
  122. package/dist/server/src/server/dev-server.js +34 -20
  123. package/dist/server/src/server/runner.d.ts.map +1 -1
  124. package/dist/server/src/server/runner.js +41 -26
  125. package/dist/server/src/services/connection/connection-manager.d.ts +85 -103
  126. package/dist/server/src/services/connection/connection-manager.d.ts.map +1 -1
  127. package/dist/server/src/services/connection/connection-manager.js +286 -241
  128. package/dist/server/src/services/connection/tool-cache.d.ts +27 -25
  129. package/dist/server/src/services/connection/tool-cache.d.ts.map +1 -1
  130. package/dist/server/src/services/connection/tool-cache.js +50 -55
  131. package/dist/server/src/services/gateway/gateway.service.d.ts +2 -0
  132. package/dist/server/src/services/gateway/gateway.service.d.ts.map +1 -1
  133. package/dist/server/src/services/gateway/gateway.service.js +15 -19
  134. package/dist/server/src/services/gateway/global-transport.d.ts +10 -0
  135. package/dist/server/src/services/gateway/global-transport.d.ts.map +1 -0
  136. package/dist/server/src/services/gateway/global-transport.js +42 -0
  137. package/dist/server/src/services/gateway/request-handlers/call-tool-handler.d.ts.map +1 -1
  138. package/dist/server/src/services/gateway/request-handlers/call-tool-handler.js +67 -65
  139. package/dist/server/src/services/gateway/request-handlers/index.d.ts +1 -1
  140. package/dist/server/src/services/gateway/request-handlers/index.d.ts.map +1 -1
  141. package/dist/server/src/services/gateway/request-handlers/index.js +1 -1
  142. package/dist/server/src/services/gateway/request-handlers/initialize-handler.d.ts +1 -4
  143. package/dist/server/src/services/gateway/request-handlers/initialize-handler.d.ts.map +1 -1
  144. package/dist/server/src/services/gateway/request-handlers/initialize-handler.js +10 -81
  145. package/dist/server/src/services/gateway/request-handlers/initialize.constants.d.ts +35 -0
  146. package/dist/server/src/services/gateway/request-handlers/initialize.constants.d.ts.map +1 -0
  147. package/dist/server/src/services/gateway/request-handlers/initialize.constants.js +44 -0
  148. package/dist/server/src/services/gateway/request-handlers/resources-handler.d.ts.map +1 -1
  149. package/dist/server/src/services/gateway/request-handlers/resources-handler.js +5 -4
  150. package/dist/server/src/services/gateway/request-handlers/system-tools-handler.d.ts.map +1 -1
  151. package/dist/server/src/services/gateway/request-handlers/system-tools-handler.js +32 -77
  152. package/dist/server/src/services/gateway/request-handlers/tools-handler.d.ts.map +1 -1
  153. package/dist/server/src/services/gateway/request-handlers/tools-handler.js +4 -3
  154. package/dist/server/src/services/gateway/tool-list-generator.d.ts.map +1 -1
  155. package/dist/server/src/services/gateway/tool-list-generator.js +37 -16
  156. package/dist/server/src/services/gateway/types.d.ts +2 -1
  157. package/dist/server/src/services/gateway/types.d.ts.map +1 -1
  158. package/dist/server/src/services/hub-manager.service.d.ts +32 -238
  159. package/dist/server/src/services/hub-manager.service.d.ts.map +1 -1
  160. package/dist/server/src/services/hub-manager.service.js +89 -267
  161. package/dist/server/src/services/hub-tools/index.d.ts +1 -3
  162. package/dist/server/src/services/hub-tools/index.d.ts.map +1 -1
  163. package/dist/server/src/services/hub-tools/index.js +1 -2
  164. package/dist/server/src/services/hub-tools/instance-matcher.d.ts +62 -0
  165. package/dist/server/src/services/hub-tools/instance-matcher.d.ts.map +1 -0
  166. package/dist/server/src/services/hub-tools/instance-matcher.js +132 -0
  167. package/dist/server/src/services/hub-tools/instance-selector.d.ts +29 -0
  168. package/dist/server/src/services/hub-tools/instance-selector.d.ts.map +1 -0
  169. package/dist/server/src/services/hub-tools/instance-selector.js +103 -0
  170. package/dist/server/src/services/hub-tools/resource-generator.d.ts +24 -1
  171. package/dist/server/src/services/hub-tools/resource-generator.d.ts.map +1 -1
  172. package/dist/server/src/services/hub-tools/resource-generator.js +259 -39
  173. package/dist/server/src/services/hub-tools/server-selector.d.ts +26 -13
  174. package/dist/server/src/services/hub-tools/server-selector.d.ts.map +1 -1
  175. package/dist/server/src/services/hub-tools/server-selector.js +44 -37
  176. package/dist/server/src/services/hub-tools/system-tool-definitions.d.ts +1 -4
  177. package/dist/server/src/services/hub-tools/system-tool-definitions.d.ts.map +1 -1
  178. package/dist/server/src/services/hub-tools/system-tool-definitions.js +17 -80
  179. package/dist/server/src/services/hub-tools/tool-search.d.ts +7 -7
  180. package/dist/server/src/services/hub-tools/tool-search.d.ts.map +1 -1
  181. package/dist/server/src/services/hub-tools/tool-search.js +10 -4
  182. package/dist/server/src/services/hub-tools/types.d.ts +2 -2
  183. package/dist/server/src/services/hub-tools/types.d.ts.map +1 -1
  184. package/dist/server/src/services/hub-tools.service.d.ts +43 -72
  185. package/dist/server/src/services/hub-tools.service.d.ts.map +1 -1
  186. package/dist/server/src/services/hub-tools.service.js +185 -110
  187. package/dist/server/src/services/search/search-core.service.d.ts +5 -5
  188. package/dist/server/src/services/search/search-core.service.js +11 -11
  189. package/dist/server/src/services/session/session-manager.d.ts +12 -256
  190. package/dist/server/src/services/session/session-manager.d.ts.map +1 -1
  191. package/dist/server/src/services/session/session-manager.js +23 -585
  192. package/dist/server/src/services/session-tracker.service.d.ts +2 -10
  193. package/dist/server/src/services/session-tracker.service.d.ts.map +1 -1
  194. package/dist/server/src/services/session-tracker.service.js +2 -53
  195. package/dist/server/src/services/system-tool-handler.d.ts.map +1 -1
  196. package/dist/server/src/services/system-tool-handler.js +7 -17
  197. package/dist/server/src/utils/composite-key.d.ts +29 -0
  198. package/dist/server/src/utils/composite-key.d.ts.map +1 -0
  199. package/dist/server/src/utils/composite-key.js +39 -0
  200. package/dist/server/src/utils/error-handler.d.ts.map +1 -1
  201. package/dist/server/src/utils/error-handler.js +3 -2
  202. package/dist/server/src/utils/index.d.ts +2 -0
  203. package/dist/server/src/utils/index.d.ts.map +1 -1
  204. package/dist/server/src/utils/index.js +2 -0
  205. package/dist/server/src/utils/instance-id.d.ts +22 -0
  206. package/dist/server/src/utils/instance-id.d.ts.map +1 -0
  207. package/dist/server/src/utils/instance-id.js +59 -0
  208. package/dist/server/src/utils/json-utils.d.ts +4 -4
  209. package/dist/server/src/utils/json-utils.d.ts.map +1 -1
  210. package/dist/server/src/utils/json-utils.js +4 -4
  211. package/dist/server/src/utils/logger/dev-logger.d.ts +2 -1
  212. package/dist/server/src/utils/logger/dev-logger.d.ts.map +1 -1
  213. package/dist/server/src/utils/logger/log-formatter.d.ts.map +1 -1
  214. package/dist/server/src/utils/logger/log-formatter.js +82 -5
  215. package/dist/server/src/utils/logger/log-modules.d.ts +15 -9
  216. package/dist/server/src/utils/logger/log-modules.d.ts.map +1 -1
  217. package/dist/server/src/utils/logger/log-modules.js +8 -6
  218. package/dist/server/src/utils/parameter-validator.d.ts +10 -0
  219. package/dist/server/src/utils/parameter-validator.d.ts.map +1 -0
  220. package/dist/server/src/utils/parameter-validator.js +53 -0
  221. package/dist/server/src/utils/process-tree.d.ts +49 -0
  222. package/dist/server/src/utils/process-tree.d.ts.map +1 -0
  223. package/dist/server/src/utils/process-tree.js +285 -0
  224. package/dist/server/src/utils/request-context.d.ts +0 -18
  225. package/dist/server/src/utils/request-context.d.ts.map +1 -1
  226. package/dist/server/src/utils/request-context.js +0 -20
  227. package/dist/server/src/utils/sort-utils.d.ts +40 -0
  228. package/dist/server/src/utils/sort-utils.d.ts.map +1 -0
  229. package/dist/server/src/utils/sort-utils.js +131 -0
  230. package/dist/server/src/utils/transports/sse-transport.d.ts +16 -1
  231. package/dist/server/src/utils/transports/sse-transport.d.ts.map +1 -1
  232. package/dist/server/src/utils/transports/sse-transport.js +55 -9
  233. package/dist/server/src/utils/transports/stdio-transport.d.ts +24 -53
  234. package/dist/server/src/utils/transports/stdio-transport.d.ts.map +1 -1
  235. package/dist/server/src/utils/transports/stdio-transport.js +66 -247
  236. package/dist/server/src/utils/transports/streamable-http-transport.d.ts +24 -1
  237. package/dist/server/src/utils/transports/streamable-http-transport.d.ts.map +1 -1
  238. package/dist/server/src/utils/transports/streamable-http-transport.js +68 -8
  239. package/dist/server/src/utils/transports/transport-factory.d.ts +9 -4
  240. package/dist/server/src/utils/transports/transport-factory.d.ts.map +1 -1
  241. package/dist/server/src/utils/transports/transport-factory.js +31 -11
  242. package/dist/server/src/utils/transports/transport.interface.d.ts +6 -0
  243. package/dist/server/src/utils/transports/transport.interface.d.ts.map +1 -1
  244. package/dist/server/src/utils/version.d.ts +11 -0
  245. package/dist/server/src/utils/version.d.ts.map +1 -0
  246. package/dist/server/src/utils/version.js +57 -0
  247. package/dist/server/tests/contract/mcp-protocol/initialize.test.js +24 -24
  248. package/dist/server/tests/contract/mcp-protocol/tools-call.test.js +49 -45
  249. package/dist/server/tests/contract/mcp-protocol/tools-list.test.js +35 -36
  250. package/dist/server/tests/evaluation/evaluation.test.js +10 -9
  251. package/dist/server/tests/integration/api/gateway.test.js +2 -2
  252. package/dist/server/tests/integration/gateway/fault-tolerance.test.js +65 -25
  253. package/dist/server/tests/integration/gateway/mcp-connection.test.js +53 -61
  254. package/dist/server/tests/server.test.js +27 -16
  255. package/dist/server/tests/temp/temp-run-docling.d.ts +2 -0
  256. package/dist/server/tests/temp/temp-run-docling.d.ts.map +1 -0
  257. package/dist/server/tests/temp/temp-run-docling.js +53 -0
  258. package/dist/server/tests/types/test-helpers.d.ts +1 -2
  259. package/dist/server/tests/types/test-helpers.d.ts.map +1 -1
  260. package/dist/server/tests/unit/config/config-loader-automatic-migration.test.d.ts +2 -0
  261. package/dist/server/tests/unit/config/config-loader-automatic-migration.test.d.ts.map +1 -0
  262. package/dist/server/tests/unit/config/config-loader-automatic-migration.test.js +199 -0
  263. package/dist/server/tests/unit/config/config-migrator.test.d.ts +2 -0
  264. package/dist/server/tests/unit/config/config-migrator.test.d.ts.map +1 -0
  265. package/dist/server/tests/unit/config/config-migrator.test.js +316 -0
  266. package/dist/server/tests/unit/config/config-saver.test.d.ts +2 -0
  267. package/dist/server/tests/unit/config/config-saver.test.d.ts.map +1 -0
  268. package/dist/server/tests/unit/config/config-saver.test.js +200 -0
  269. package/dist/server/tests/unit/config/config.schema.test.d.ts +2 -0
  270. package/dist/server/tests/unit/config/config.schema.test.d.ts.map +1 -0
  271. package/dist/server/tests/unit/config/config.schema.test.js +347 -0
  272. package/dist/server/tests/unit/server/runner.test.js +86 -62
  273. package/dist/server/tests/unit/services/connection/connection-manager.test.d.ts +2 -0
  274. package/dist/server/tests/unit/services/connection/connection-manager.test.d.ts.map +1 -0
  275. package/dist/server/tests/unit/services/connection/connection-manager.test.js +112 -0
  276. package/dist/server/tests/unit/services/hub-manager-service.test.js +112 -46
  277. package/dist/server/tests/unit/services/hub-manager.test.js +25 -15
  278. package/dist/server/tests/unit/services/hub-tools/instance-selector.test.d.ts +2 -0
  279. package/dist/server/tests/unit/services/hub-tools/instance-selector.test.d.ts.map +1 -0
  280. package/dist/server/tests/unit/services/hub-tools/instance-selector.test.js +195 -0
  281. package/dist/server/tests/unit/services/hub-tools/server-selector.test.d.ts +2 -0
  282. package/dist/server/tests/unit/services/hub-tools/server-selector.test.d.ts.map +1 -0
  283. package/dist/server/tests/unit/services/hub-tools/server-selector.test.js +190 -0
  284. package/dist/server/tests/unit/services/hub-tools.service.test.js +560 -320
  285. package/dist/server/tests/unit/services/instance-matcher.test.d.ts +2 -0
  286. package/dist/server/tests/unit/services/instance-matcher.test.d.ts.map +1 -0
  287. package/dist/server/tests/unit/services/instance-matcher.test.js +256 -0
  288. package/dist/server/tests/unit/services/session-manager.test.js +26 -436
  289. package/dist/server/tests/unit/utils/config.test.js +88 -186
  290. package/dist/server/tests/unit/utils/json-utils.test.js +18 -18
  291. package/dist/server/tests/unit/utils/logger-formatter.test.d.ts +2 -0
  292. package/dist/server/tests/unit/utils/logger-formatter.test.d.ts.map +1 -0
  293. package/dist/server/tests/unit/utils/logger-formatter.test.js +66 -0
  294. package/dist/server/tests/unit/utils/parameter-validator.test.d.ts +2 -0
  295. package/dist/server/tests/unit/utils/parameter-validator.test.d.ts.map +1 -0
  296. package/dist/server/tests/unit/utils/parameter-validator.test.js +63 -0
  297. package/dist/server/tests/unit/utils/process-tree.test.d.ts +2 -0
  298. package/dist/server/tests/unit/utils/process-tree.test.d.ts.map +1 -0
  299. package/dist/server/tests/unit/utils/process-tree.test.js +129 -0
  300. package/dist/server/tests/unit/utils/request-context.test.js +5 -24
  301. package/dist/server/tests/unit/utils/sort-utils.test.d.ts +2 -0
  302. package/dist/server/tests/unit/utils/sort-utils.test.d.ts.map +1 -0
  303. package/dist/server/tests/unit/utils/sort-utils.test.js +220 -0
  304. package/dist/server/tests/unit/utils/transport-factory.test.d.ts +2 -0
  305. package/dist/server/tests/unit/utils/transport-factory.test.d.ts.map +1 -0
  306. package/dist/server/tests/unit/utils/transport-factory.test.js +55 -0
  307. package/package.json +1 -1
  308. package/dist/client/assets/ResourceDetailView-Bf-1ffbk.js +0 -1
  309. package/dist/client/assets/ResourcesView-CjMklkyv.css +0 -1
  310. package/dist/client/assets/ResourcesView-g5x4xCPh.js +0 -1
  311. package/dist/client/assets/ServerDashboard-Chpne8Q0.css +0 -1
  312. package/dist/client/assets/ServerDashboard-G8Wmp4hF.js +0 -2
  313. package/dist/client/assets/ServerListView-dV2XrPjo.js +0 -32
  314. package/dist/client/assets/ServerStatusTags.vue_vue_type_script_setup_true_lang-BHiTFM7-.js +0 -1
  315. package/dist/client/assets/SessionsView-Ckd38lj1.js +0 -1
  316. package/dist/client/assets/SettingsView-BJUdepEQ.js +0 -1
  317. package/dist/client/assets/ToolCallDialog-C_bTCpHC.js +0 -1
  318. package/dist/client/assets/ToolsView-0c2eputu.js +0 -1
  319. package/dist/client/assets/el-form-item-BVMLpmVC.css +0 -1
  320. package/dist/client/assets/el-form-item-ClFnj49k.js +0 -12
  321. package/dist/client/assets/el-input-CDnuSKVZ.js +0 -1
  322. package/dist/client/assets/el-input-CmuHb8HS.css +0 -1
  323. package/dist/client/assets/el-overlay-B2ZKM6Up.css +0 -1
  324. package/dist/client/assets/el-overlay-CzMkXyYy.js +0 -1
  325. package/dist/client/assets/el-select-DvjGddk_.js +0 -1
  326. package/dist/client/assets/el-tab-pane-C_DQMcwe.js +0 -1
  327. package/dist/client/assets/el-table-column-CASRIbZM.js +0 -1
  328. package/dist/client/assets/el-table-column-T_mV9jNw.css +0 -1
  329. package/dist/client/assets/el-tag-DjxZVOpb.css +0 -1
  330. package/dist/client/assets/el-tag-npbwux4f.js +0 -1
  331. package/dist/client/assets/index-CCnAxNF8.js +0 -2
  332. package/dist/client/assets/index-d1DZeSfz.js +0 -1
  333. package/dist/client/assets/vnode-CHomNjgN.js +0 -1
@@ -0,0 +1,132 @@
1
+ /**
2
+ * Instance Matcher Service
3
+ * Provides intelligent instance selection based on tags and connection status.
4
+ */
5
+ /**
6
+ * Calculates the match score between an instance and requested tags.
7
+ *
8
+ * The score ranges from 0.0 (no match) to 1.0 (perfect match).
9
+ * Calculated as the ratio of matching tags to total requested tags.
10
+ *
11
+ * @param instance - The service instance to evaluate
12
+ * @param requestedTags - The tags to match against
13
+ * @returns Match score between 0.0 and 1.0
14
+ */
15
+ export function calculateMatchScore(instance, requestedTags) {
16
+ // If no tags requested, perfect match
17
+ if (!requestedTags || Object.keys(requestedTags).length === 0) {
18
+ return 1.0;
19
+ }
20
+ const instanceTags = instance.tags || {};
21
+ const requestedTagKeys = Object.keys(requestedTags);
22
+ if (requestedTagKeys.length === 0) {
23
+ return 1.0;
24
+ }
25
+ // Count matching tags
26
+ let matchCount = 0;
27
+ for (const [key, value] of Object.entries(requestedTags)) {
28
+ if (instanceTags[key] === value) {
29
+ matchCount++;
30
+ }
31
+ }
32
+ return matchCount / requestedTagKeys.length;
33
+ }
34
+ /**
35
+ * Filters instances to only include enabled ones.
36
+ *
37
+ * @param instances - Array of instances to filter
38
+ * @returns Array of enabled instances
39
+ */
40
+ export function filterEnabledInstances(instances) {
41
+ return instances.filter((instance) => instance.enabled !== false);
42
+ }
43
+ /**
44
+ * Sorts instances by connection status (connected first).
45
+ *
46
+ * Preserves the original order within each status group.
47
+ *
48
+ * @param instances - Array of instances with connection status
49
+ * @returns Sorted array with connected instances first
50
+ */
51
+ export function sortByConnectionStatus(instances) {
52
+ const connected = [];
53
+ const disconnected = [];
54
+ for (const instance of instances) {
55
+ if (instance.connected === true) {
56
+ connected.push(instance);
57
+ }
58
+ else {
59
+ disconnected.push(instance);
60
+ }
61
+ }
62
+ return [...connected, ...disconnected];
63
+ }
64
+ /**
65
+ * Selects the best matching instance based on tags and connection status.
66
+ *
67
+ * Selection priority:
68
+ * 1. Only consider enabled instances
69
+ * 2. Prioritize connected instances over disconnected ones (ALWAYS prefer connected if available)
70
+ * 3. Among connected instances, select the one with highest tag match score
71
+ * 4. Among disconnected instances, select the one with highest tag match score
72
+ * 5. Only return undefined if NO connected instances AND tags requested but no match
73
+ *
74
+ * @param instances - Array of instances to choose from
75
+ * @param requestedTags - Optional tags to match
76
+ * @returns The best matching instance, or undefined if no suitable instance found
77
+ */
78
+ export function selectBestMatch(instances, requestedTags) {
79
+ if (instances.length === 0) {
80
+ return undefined;
81
+ }
82
+ // Filter to only enabled instances
83
+ const enabledInstances = filterEnabledInstances(instances);
84
+ if (enabledInstances.length === 0) {
85
+ return undefined;
86
+ }
87
+ // Check if tags are requested
88
+ const hasRequestedTags = !!(requestedTags && Object.keys(requestedTags).length > 0);
89
+ // Sort by connection status (connected first)
90
+ const sortedInstances = sortByConnectionStatus(enabledInstances);
91
+ // Group by connection status
92
+ const connectedInstances = sortedInstances.filter((i) => i.connected === true);
93
+ const disconnectedInstances = sortedInstances.filter((i) => i.connected !== true);
94
+ // Always prefer connected instances if available, even with 0 tag match
95
+ if (connectedInstances.length > 0) {
96
+ // For connected instances, always return the best one (never undefined for connected)
97
+ return findBestMatchingInstance(connectedInstances, requestedTags, false);
98
+ }
99
+ // Only for disconnected instances, return undefined if tags requested but no match
100
+ if (disconnectedInstances.length > 0) {
101
+ return findBestMatchingInstance(disconnectedInstances, requestedTags, hasRequestedTags);
102
+ }
103
+ return undefined;
104
+ }
105
+ /**
106
+ * Helper to find the instance with the highest match score.
107
+ *
108
+ * @param instances - Array of instances to evaluate
109
+ * @param requestedTags - Tags to match against
110
+ * @param hasRequestedTags - Whether tags were explicitly requested
111
+ * @returns The instance with highest score, or undefined if no match found and tags requested
112
+ */
113
+ function findBestMatchingInstance(instances, requestedTags, hasRequestedTags) {
114
+ if (instances.length === 0) {
115
+ return undefined;
116
+ }
117
+ let bestInstance;
118
+ let bestScore = -1;
119
+ for (const instance of instances) {
120
+ const score = calculateMatchScore(instance, requestedTags);
121
+ if (score > bestScore) {
122
+ bestScore = score;
123
+ bestInstance = instance;
124
+ }
125
+ }
126
+ // If tags were requested and best score is 0 (no match), return undefined
127
+ if (hasRequestedTags && bestScore === 0) {
128
+ return undefined;
129
+ }
130
+ // Otherwise return the best instance (or first instance if all scores equal)
131
+ return bestInstance || instances[0];
132
+ }
@@ -0,0 +1,29 @@
1
+ import type { ServerConfig, ServerInstance } from '../../../shared/models/server.model.js';
2
+ /**
3
+ * Error thrown when tag-match-unique instance selection fails.
4
+ * Passes raw data so the error class itself can format the message.
5
+ */
6
+ export declare class TagMatchUniqueError extends Error {
7
+ readonly instanceCount: number;
8
+ readonly requestTags?: Record<string, string> | undefined;
9
+ readonly availableInstances?: Record<number, Record<string, string>> | undefined;
10
+ constructor(instanceCount: number, requestTags?: Record<string, string> | undefined, availableInstances?: Record<number, Record<string, string>> | undefined);
11
+ }
12
+ /**
13
+ * Instance selector for multi-instance servers
14
+ * Implements three selection strategies: random, round-robin, and tag-match-unique
15
+ */
16
+ export declare class InstanceSelector {
17
+ private static roundRobinCounters;
18
+ /**
19
+ * Select best instance based on configured strategy
20
+ */
21
+ static selectInstance(serverName: string, serverConfig: ServerConfig, requestOptions?: {
22
+ sessionId?: string;
23
+ tags?: Record<string, string>;
24
+ }): ServerInstance | undefined;
25
+ private static selectRandomInstance;
26
+ private static selectRoundRobinInstance;
27
+ private static selectTagMatchUniqueInstance;
28
+ }
29
+ //# sourceMappingURL=instance-selector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"instance-selector.d.ts","sourceRoot":"","sources":["../../../../../src/services/hub-tools/instance-selector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAGnF;;;GAGG;AACH,qBAAa,mBAAoB,SAAQ,KAAK;aAE1B,aAAa,EAAE,MAAM;aACrB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;aACpC,kBAAkB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;gBAF3D,aAAa,EAAE,MAAM,EACrB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,YAAA,EACpC,kBAAkB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,YAAA;CAmB9E;AAED;;;GAGG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,MAAM,CAAC,kBAAkB,CAA6B;IAE9D;;OAEG;IACH,MAAM,CAAC,cAAc,CACnB,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,YAAY,EAC1B,cAAc,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,GACrE,cAAc,GAAG,SAAS;IA+B7B,OAAO,CAAC,MAAM,CAAC,oBAAoB;IAKnC,OAAO,CAAC,MAAM,CAAC,wBAAwB;IAUvC,OAAO,CAAC,MAAM,CAAC,4BAA4B;CAiC5C"}
@@ -0,0 +1,103 @@
1
+ import { InstanceSelectionStrategy } from '../../models/server.model.js';
2
+ /**
3
+ * Error thrown when tag-match-unique instance selection fails.
4
+ * Passes raw data so the error class itself can format the message.
5
+ */
6
+ export class TagMatchUniqueError extends Error {
7
+ instanceCount;
8
+ requestTags;
9
+ availableInstances;
10
+ constructor(instanceCount, requestTags, availableInstances) {
11
+ let message;
12
+ if (!requestTags) {
13
+ // Format available instances as index:tags for easy selection
14
+ const instancesStr = availableInstances
15
+ ? Object.entries(availableInstances)
16
+ .map(([index, tags]) => `${index}:${JSON.stringify(tags)}`)
17
+ .join(', ')
18
+ : '';
19
+ message = `No tags provided for tag-match-unique strategy with ${instanceCount} instances. Available: [${instancesStr}]. Pass matching tags to select.`;
20
+ }
21
+ else if (instanceCount === 0) {
22
+ message = `No instance found matching tags: ${JSON.stringify(requestTags)}`;
23
+ }
24
+ else {
25
+ message = `Multiple instances match tags: ${JSON.stringify(requestTags)}. Expected unique match.`;
26
+ }
27
+ super(message);
28
+ this.instanceCount = instanceCount;
29
+ this.requestTags = requestTags;
30
+ this.availableInstances = availableInstances;
31
+ this.name = 'TagMatchUniqueError';
32
+ }
33
+ }
34
+ /**
35
+ * Instance selector for multi-instance servers
36
+ * Implements three selection strategies: random, round-robin, and tag-match-unique
37
+ */
38
+ export class InstanceSelector {
39
+ static roundRobinCounters = new Map();
40
+ /**
41
+ * Select best instance based on configured strategy
42
+ */
43
+ static selectInstance(serverName, serverConfig, requestOptions) {
44
+ const { instances } = serverConfig;
45
+ const instanceSelectionStrategy = serverConfig.template.instanceSelectionStrategy || InstanceSelectionStrategy.RANDOM;
46
+ // Filter enabled instances
47
+ const enabledInstances = instances.filter((instance) => instance.enabled !== false);
48
+ if (enabledInstances.length === 0) {
49
+ return undefined;
50
+ }
51
+ // Single instance case - return directly
52
+ if (enabledInstances.length === 1) {
53
+ return enabledInstances[0];
54
+ }
55
+ switch (instanceSelectionStrategy) {
56
+ case InstanceSelectionStrategy.RANDOM:
57
+ return this.selectRandomInstance(enabledInstances);
58
+ case InstanceSelectionStrategy.ROUND_ROBIN:
59
+ return this.selectRoundRobinInstance(serverName, enabledInstances);
60
+ case InstanceSelectionStrategy.TAG_MATCH_UNIQUE:
61
+ return this.selectTagMatchUniqueInstance(enabledInstances, requestOptions?.tags);
62
+ default:
63
+ return enabledInstances[0]; // Fallback to first instance
64
+ }
65
+ }
66
+ static selectRandomInstance(instances) {
67
+ const randomIndex = Math.floor(Math.random() * instances.length);
68
+ return instances[randomIndex];
69
+ }
70
+ static selectRoundRobinInstance(serverName, instances) {
71
+ const counter = this.roundRobinCounters.get(serverName) || 0;
72
+ const selectedInstance = instances[counter % instances.length];
73
+ this.roundRobinCounters.set(serverName, (counter + 1) % instances.length);
74
+ return selectedInstance;
75
+ }
76
+ static selectTagMatchUniqueInstance(instances, requestTags) {
77
+ // Build available instances map with index:tags format
78
+ const availableInstances = {};
79
+ instances.forEach((instance, index) => {
80
+ availableInstances[index] = instance.tags || {};
81
+ });
82
+ if (!requestTags || Object.keys(requestTags).length === 0) {
83
+ // If no request tags provided, must have exactly one instance to avoid ambiguity
84
+ if (instances.length === 1) {
85
+ return instances[0];
86
+ }
87
+ else {
88
+ throw new TagMatchUniqueError(instances.length, undefined, availableInstances);
89
+ }
90
+ }
91
+ const matchingInstances = instances.filter((instance) => {
92
+ if (!instance.tags)
93
+ return false;
94
+ // Check if all request tags match instance tags
95
+ return Object.entries(requestTags).every(([key, value]) => instance.tags[key] === value);
96
+ });
97
+ // Must have exactly one matching instance
98
+ if (matchingInstances.length !== 1) {
99
+ throw new TagMatchUniqueError(matchingInstances.length, requestTags, availableInstances);
100
+ }
101
+ return matchingInstances[0];
102
+ }
103
+ }
@@ -1,5 +1,26 @@
1
1
  import type { Resource } from '../../../shared/models/resource.model.js';
2
2
  import type { ServerStatus } from '../../../shared/types/common.types.js';
3
+ /**
4
+ * Clears the Hub to MCP URI mapping.
5
+ * Should be called before regenerating resources.
6
+ */
7
+ export declare function clearHubToMcpUriMap(): void;
8
+ /**
9
+ * URI for the use guide resource.
10
+ */
11
+ export declare const USE_GUIDE_URI = "hub://use-guide";
12
+ /**
13
+ * Name of the use guide resource.
14
+ */
15
+ export declare const USE_GUIDE_NAME = "MCP Hub Lite Use Guide";
16
+ /**
17
+ * Description of the use guide resource.
18
+ */
19
+ export declare const USE_GUIDE_DESCRIPTION = "Comprehensive guide to using MCP Hub Lite gateway and its features";
20
+ /**
21
+ * MIME type for the use guide resource.
22
+ */
23
+ export declare const USE_GUIDE_MIME_TYPE = "text/markdown";
3
24
  /**
4
25
  * Server metadata resource content.
5
26
  */
@@ -7,10 +28,12 @@ export interface ServerMetadata {
7
28
  name: string;
8
29
  status: ServerStatus;
9
30
  toolsCount: number;
31
+ tools: Record<string, string>;
10
32
  resourcesCount: number;
11
33
  tags: Record<string, string>;
12
34
  lastHeartbeat: number;
13
35
  uptime: number;
36
+ description: string;
14
37
  }
15
38
  /**
16
39
  * Generates dynamic Hub resources based on currently connected MCP servers.
@@ -56,5 +79,5 @@ export declare function generateDynamicResources(): Resource[];
56
79
  * const tools = await readResource('hub://servers/my-mcp-server/tools');
57
80
  * ```
58
81
  */
59
- export declare function readResource(uri: string): Promise<ServerMetadata | Resource[]>;
82
+ export declare function readResource(uri: string): Promise<ServerMetadata | Resource[] | string | unknown>;
60
83
  //# sourceMappingURL=resource-generator.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"resource-generator.d.ts","sourceRoot":"","sources":["../../../../../src/services/hub-tools/resource-generator.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kCAAkC,CAAC;AACjE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAGlE;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,YAAY,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,wBAAwB,IAAI,QAAQ,EAAE,CA6BrD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAsB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,QAAQ,EAAE,CAAC,CAgDpF"}
1
+ {"version":3,"file":"resource-generator.d.ts","sourceRoot":"","sources":["../../../../../src/services/hub-tools/resource-generator.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kCAAkC,CAAC;AACjE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAUlE;;;GAGG;AACH,wBAAgB,mBAAmB,IAAI,IAAI,CAE1C;AA6ID;;GAEG;AACH,eAAO,MAAM,aAAa,oBAAoB,CAAC;AAE/C;;GAEG;AACH,eAAO,MAAM,cAAc,2BAA2B,CAAC;AAEvD;;GAEG;AACH,eAAO,MAAM,qBAAqB,uEACoC,CAAC;AAEvE;;GAEG;AACH,eAAO,MAAM,mBAAmB,kBAAkB,CAAC;AAEnD;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,YAAY,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,cAAc,EAAE,MAAM,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,wBAAwB,IAAI,QAAQ,EAAE,CAgErD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAsB,YAAY,CAChC,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,cAAc,GAAG,QAAQ,EAAE,GAAG,MAAM,GAAG,OAAO,CAAC,CAyGzD"}
@@ -1,6 +1,149 @@
1
+ import { fileURLToPath } from 'url';
2
+ import { dirname, join } from 'path';
3
+ import fs from 'fs';
1
4
  import { hubManager } from '../hub-manager.service.js';
2
5
  import { mcpConnectionManager } from '../mcp-connection-manager.js';
3
- import { hasValidId, selectBestInstance } from './server-selector.js';
6
+ import { hasValidId, selectBestInstance, getServerDescription } from './server-selector.js';
7
+ /**
8
+ * Maps Hub URI to original MCP URI for resource forwarding.
9
+ * Key: Hub URI (e.g., "hub://servers/exa-ai/0/tools/list")
10
+ * Value: Original MCP URI (e.g., "exa://tools/list")
11
+ */
12
+ const hubToMcpUriMap = new Map();
13
+ /**
14
+ * Clears the Hub to MCP URI mapping.
15
+ * Should be called before regenerating resources.
16
+ */
17
+ export function clearHubToMcpUriMap() {
18
+ hubToMcpUriMap.clear();
19
+ }
20
+ /**
21
+ * Maps an MCP native URI to hub format.
22
+ * Example: "exa://tools/list" -> "hub://servers/exa-ai/0/tools/list"
23
+ * Also registers the mapping in hubToMcpUriMap for reverse lookup.
24
+ *
25
+ * @param serverName - The server name
26
+ * @param instanceIndex - The instance index
27
+ * @param mcpUri - The native MCP URI (e.g., "exa://tools/list")
28
+ * @returns The hub-formatted URI
29
+ */
30
+ function getMcpPathFromUri(mcpUri) {
31
+ return mcpUri.replace(/^[a-zA-Z][a-zA-Z0-9+.-]*:(\/\/)?/, '');
32
+ }
33
+ function mapMcpUriToHub(serverName, instanceIndex, mcpUri) {
34
+ // Remove the scheme prefix (e.g., "exa://" or "exa:")
35
+ const mcpPath = getMcpPathFromUri(mcpUri);
36
+ const hubUri = `hub://servers/${serverName}/${instanceIndex}/${mcpPath}`;
37
+ // Register mapping for reverse lookup in readResource
38
+ hubToMcpUriMap.set(hubUri, mcpUri);
39
+ return hubUri;
40
+ }
41
+ /**
42
+ * Restores a missing Hub -> MCP URI mapping by scanning the current instance resources.
43
+ */
44
+ function restoreMcpUriMapping(serverName, instanceIndex, _instanceId, mcpPath) {
45
+ const instanceResources = mcpConnectionManager.getResources(serverName, instanceIndex);
46
+ for (const resource of instanceResources) {
47
+ const originalUri = resource.uri;
48
+ if (typeof originalUri !== 'string') {
49
+ continue;
50
+ }
51
+ if (getMcpPathFromUri(originalUri) !== mcpPath) {
52
+ continue;
53
+ }
54
+ const hubUri = `hub://servers/${serverName}/${instanceIndex}/${mcpPath}`;
55
+ hubToMcpUriMap.set(hubUri, originalUri);
56
+ return originalUri;
57
+ }
58
+ return null;
59
+ }
60
+ /**
61
+ * Parses a hub URI and extracts components.
62
+ * Supports:
63
+ * - hub://servers/{name} - Server metadata
64
+ * - hub://servers/{name}/tools - Tools list
65
+ * - hub://servers/{name}/resources - Resources list
66
+ * - hub://servers/{name}/{instanceIndex}/{mcpPath} - MCP native resource forwarding
67
+ *
68
+ * @param uri - The hub URI to parse
69
+ * @returns Parsed components, 'unknown' if format is valid but resource type is unknown, or null if format is invalid
70
+ */
71
+ function parseHubUri(uri) {
72
+ if (!uri.startsWith('hub://')) {
73
+ return null;
74
+ }
75
+ const parts = uri.replace('hub://', '').split('/');
76
+ if (parts.length < 2 || parts[0] !== 'servers') {
77
+ return null;
78
+ }
79
+ const serverName = parts[1];
80
+ // hub://servers/{name} - no instance index
81
+ if (parts.length === 2) {
82
+ return { serverName };
83
+ }
84
+ // hub://servers/{name}/tools or hub://servers/{name}/resources
85
+ // These are list requests, not MCP forwarding
86
+ if (parts.length === 3) {
87
+ const resourceType = parts[2];
88
+ if (resourceType === 'tools' || resourceType === 'resources') {
89
+ return { serverName, listType: resourceType };
90
+ }
91
+ // Unknown resource type but valid URI format
92
+ return 'unknown';
93
+ }
94
+ // hub://servers/{name}/{instanceIndex}/{mcpPath}
95
+ const instanceIndex = parseInt(parts[2], 10);
96
+ if (isNaN(instanceIndex) || parts.length < 4) {
97
+ return null;
98
+ }
99
+ const mcpPath = parts.slice(3).join('/');
100
+ return { serverName, instanceIndex, mcpPath };
101
+ }
102
+ /**
103
+ * Path to the use guide Markdown file.
104
+ */
105
+ const __filename = fileURLToPath(import.meta.url);
106
+ const __dirname = dirname(__filename);
107
+ const USE_GUIDE_PATH = join(__dirname, 'use-guide.md');
108
+ /**
109
+ * Loads the use guide content from the Markdown file.
110
+ *
111
+ * @returns {string} Markdown formatted use guide content
112
+ */
113
+ function loadUseGuideContent() {
114
+ try {
115
+ return fs.readFileSync(USE_GUIDE_PATH, 'utf-8');
116
+ }
117
+ catch {
118
+ // Fallback in case the file can't be read
119
+ return `# MCP Hub Lite Use Guide
120
+
121
+ ## Overview
122
+
123
+ MCP Hub Lite is a lightweight MCP (Model Context Protocol) gateway that acts as a unified interface between AI assistants and multiple backend MCP servers.
124
+
125
+ ## Note
126
+
127
+ The complete use guide is currently unavailable. Please check the MCP Hub Lite documentation at https://github.com/your-org/mcp-hub-lite for more information.
128
+ `;
129
+ }
130
+ }
131
+ /**
132
+ * URI for the use guide resource.
133
+ */
134
+ export const USE_GUIDE_URI = 'hub://use-guide';
135
+ /**
136
+ * Name of the use guide resource.
137
+ */
138
+ export const USE_GUIDE_NAME = 'MCP Hub Lite Use Guide';
139
+ /**
140
+ * Description of the use guide resource.
141
+ */
142
+ export const USE_GUIDE_DESCRIPTION = 'Comprehensive guide to using MCP Hub Lite gateway and its features';
143
+ /**
144
+ * MIME type for the use guide resource.
145
+ */
146
+ export const USE_GUIDE_MIME_TYPE = 'text/markdown';
4
147
  /**
5
148
  * Generates dynamic Hub resources based on currently connected MCP servers.
6
149
  *
@@ -20,25 +163,58 @@ import { hasValidId, selectBestInstance } from './server-selector.js';
20
163
  */
21
164
  export function generateDynamicResources() {
22
165
  const resources = [];
166
+ clearHubToMcpUriMap();
167
+ // Add use-guide resource first - it's always available
168
+ resources.push({
169
+ uri: USE_GUIDE_URI,
170
+ name: USE_GUIDE_NAME,
171
+ description: USE_GUIDE_DESCRIPTION,
172
+ mimeType: USE_GUIDE_MIME_TYPE
173
+ // System resources don't have serverName/serverIndex
174
+ });
23
175
  // Use the same access pattern as tools - directly access manager cache
24
176
  const servers = hubManager.getAllServers();
25
177
  for (const server of servers) {
26
- if (!hasValidId(server) || !server.config.enabled) {
178
+ if (!hasValidId(server)) {
27
179
  continue;
28
180
  }
29
- const bestInstance = selectBestInstance(server.name);
30
- if (!bestInstance || !bestInstance.instance.id) {
181
+ // Check if any instance is enabled
182
+ const hasEnabledInstance = server.config.instances.some((i) => i.enabled !== false);
183
+ if (!hasEnabledInstance) {
31
184
  continue;
32
185
  }
33
- const instanceId = bestInstance.instance.id;
34
- // Server metadata resource
35
- resources.push({
36
- uri: `hub://servers/${server.name}`,
37
- name: `Server: ${server.name}`,
38
- description: server.config.description || `Connected MCP server: ${server.name}`,
39
- mimeType: 'application/json',
40
- serverId: instanceId
41
- });
186
+ // Iterate over all instances to expose each instance's resources
187
+ for (const instance of server.config.instances) {
188
+ if (instance.enabled === false) {
189
+ continue;
190
+ }
191
+ const instanceIndex = instance.index;
192
+ // Server metadata resource (one per server, not per instance)
193
+ if (instanceIndex === 0) {
194
+ resources.push({
195
+ uri: `hub://servers/${server.name}`,
196
+ name: `Server: ${server.name}`,
197
+ description: getServerDescription(server.config, server.name),
198
+ mimeType: 'application/json',
199
+ serverName: server.name,
200
+ serverIndex: instanceIndex
201
+ });
202
+ }
203
+ // Get MCP native resources and map to hub format
204
+ const instanceIdx = instanceIndex ?? 0;
205
+ const mcpResources = mcpConnectionManager.getResources(server.name, instanceIdx);
206
+ for (const res of mcpResources) {
207
+ // Format: Resource: {ServerName} - {Index}: {Native Name}
208
+ const displayName = `Resource:${server.name} - ${instanceIdx}:${res.name}`;
209
+ resources.push({
210
+ uri: mapMcpUriToHub(server.name, instanceIdx, res.uri),
211
+ name: displayName,
212
+ description: res.description,
213
+ mimeType: res.mimeType
214
+ // No serverId - instanceIndex is embedded in the URI
215
+ });
216
+ }
217
+ }
42
218
  }
43
219
  return resources;
44
220
  }
@@ -73,44 +249,88 @@ export async function readResource(uri) {
73
249
  if (!uri.startsWith('hub://')) {
74
250
  throw new Error(`Invalid Hub resource URI: ${uri}. Must start with 'hub://'`);
75
251
  }
252
+ // Check for use-guide resource first
253
+ if (uri === USE_GUIDE_URI) {
254
+ return loadUseGuideContent();
255
+ }
76
256
  // Parse URI
77
- const uriParts = uri.replace('hub://', '').split('/');
78
- if (uriParts.length < 2 || uriParts[0] !== 'servers') {
257
+ const parsed = parseHubUri(uri);
258
+ if (!parsed) {
79
259
  throw new Error(`Invalid Hub resource URI format: ${uri}`);
80
260
  }
81
- const serverName = uriParts[1];
82
- const resourceType = uriParts[2]; // 'tools', 'resources', or undefined for server metadata
83
- // Check if server exists and is connected
84
- const serverInfo = selectBestInstance(serverName);
85
- if (!serverInfo) {
86
- throw new Error(`Server not found or not connected: ${serverName}`);
87
- }
88
- const instanceId = serverInfo.instance.id;
89
- // Return appropriate content based on resource type
90
- if (!resourceType) {
91
- // Server metadata
92
- const serverConfig = hubManager.getServerByName(serverName);
93
- const tools = mcpConnectionManager.getTools(instanceId);
94
- const resources = mcpConnectionManager.getResources(instanceId);
261
+ // Handle unknown resource type
262
+ if (parsed === 'unknown') {
263
+ const parts = uri.replace('hub://', '').split('/');
264
+ const resourceType = parts[2];
265
+ throw new Error(`Unknown resource type: ${resourceType}`);
266
+ }
267
+ const { serverName, instanceIndex, mcpPath, listType } = parsed;
268
+ // Find server config
269
+ const serverConfig = hubManager.getServerByName(serverName);
270
+ if (!serverConfig) {
271
+ throw new Error(`Server not found: ${serverName}`);
272
+ }
273
+ // If no instanceIndex, check if this is a list request or metadata request
274
+ if (instanceIndex === undefined) {
275
+ // Handle list requests first
276
+ if (listType) {
277
+ // Use selectBestInstance to get an instance for the list
278
+ const serverInfo = selectBestInstance(serverName);
279
+ if (!serverInfo) {
280
+ throw new Error(`Server not found or not connected: ${serverName}`);
281
+ }
282
+ const instanceIndex = serverInfo.instance.index;
283
+ if (listType === 'tools') {
284
+ return mcpConnectionManager.getTools(serverName, instanceIndex);
285
+ }
286
+ else {
287
+ return mcpConnectionManager.getResources(serverName, instanceIndex);
288
+ }
289
+ }
290
+ // Server metadata request - use selectBestInstance to get runtime properties
291
+ const serverInfo = selectBestInstance(serverName);
292
+ if (!serverInfo) {
293
+ throw new Error(`Server not found or not connected: ${serverName}`);
294
+ }
295
+ const instanceIndex = serverInfo.instance.index;
296
+ const tools = mcpConnectionManager.getTools(serverName, instanceIndex);
297
+ const resources = mcpConnectionManager.getResources(serverName, instanceIndex);
298
+ // Build tool name to description map
299
+ const toolsMap = {};
300
+ for (const tool of tools) {
301
+ toolsMap[tool.name] = tool.description || '';
302
+ }
95
303
  return {
96
304
  name: serverName,
97
305
  status: serverInfo.instance.status,
98
306
  toolsCount: tools.length,
307
+ tools: toolsMap,
99
308
  resourcesCount: resources.length,
100
- tags: serverConfig?.tags || {},
309
+ tags: serverInfo.instance.tags || {},
101
310
  lastHeartbeat: serverInfo.instance.lastHeartbeat,
102
- uptime: serverInfo.instance.uptime
311
+ uptime: serverInfo.instance.uptime,
312
+ description: getServerDescription(serverConfig, serverName)
103
313
  };
104
314
  }
105
- else if (resourceType === 'tools') {
106
- // Tools list
107
- return mcpConnectionManager.getTools(instanceId);
315
+ // MCP native resource forwarding: hub://servers/{name}/{instanceIndex}/{mcpPath}
316
+ // Find the specific instance by index
317
+ const targetInstance = serverConfig.instances.find((i) => i.index === instanceIndex && i.enabled !== false);
318
+ if (!targetInstance) {
319
+ throw new Error(`Instance ${instanceIndex} not found or not enabled for server: ${serverName}`);
108
320
  }
109
- else if (resourceType === 'resources') {
110
- // Resources list
111
- return mcpConnectionManager.getResources(instanceId);
321
+ const instanceId = targetInstance.id;
322
+ // If mcpPath is empty, return instance-level info
323
+ if (!mcpPath) {
324
+ return mcpConnectionManager.getResources(serverName, instanceIndex);
112
325
  }
113
- else {
114
- throw new Error(`Unknown resource type: ${resourceType}`);
326
+ // Forward to MCP server for actual resource read
327
+ // Use the mapping to get the original MCP URI (hub://servers/exa-ai/0/tools/list -> exa://tools/list)
328
+ let originalMcpUri = hubToMcpUriMap.get(uri);
329
+ if (!originalMcpUri) {
330
+ originalMcpUri = restoreMcpUriMapping(serverName, instanceIndex, instanceId, mcpPath);
331
+ }
332
+ if (!originalMcpUri) {
333
+ throw new Error(`MCP URI not found in mapping for: ${uri}`);
115
334
  }
335
+ return mcpConnectionManager.readResource(serverName, instanceIndex, originalMcpUri);
116
336
  }