@rekog/mcp-nest 1.9.10 → 2.0.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (364) hide show
  1. package/README.md +76 -29
  2. package/dist/index.d.ts +0 -1
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +0 -1
  5. package/dist/index.js.map +1 -1
  6. package/dist/mcp/decorators/constants.d.ts +1 -0
  7. package/dist/mcp/decorators/constants.d.ts.map +1 -1
  8. package/dist/mcp/decorators/constants.js +2 -1
  9. package/dist/mcp/decorators/constants.js.map +1 -1
  10. package/dist/mcp/decorators/index.d.ts +3 -1
  11. package/dist/mcp/decorators/index.d.ts.map +1 -1
  12. package/dist/mcp/decorators/index.js +3 -1
  13. package/dist/mcp/decorators/index.js.map +1 -1
  14. package/dist/mcp/decorators/mcp-controller.decorator.d.ts +6 -0
  15. package/dist/mcp/decorators/mcp-controller.decorator.d.ts.map +1 -0
  16. package/dist/mcp/decorators/mcp-controller.decorator.js +43 -0
  17. package/dist/mcp/decorators/mcp-controller.decorator.js.map +1 -0
  18. package/dist/mcp/decorators/mcp-message-pattern.d.ts +3 -0
  19. package/dist/mcp/decorators/mcp-message-pattern.d.ts.map +1 -0
  20. package/dist/mcp/decorators/mcp-message-pattern.js +13 -0
  21. package/dist/mcp/decorators/mcp-message-pattern.js.map +1 -0
  22. package/dist/mcp/decorators/prompt.decorator.d.ts +4 -1
  23. package/dist/mcp/decorators/prompt.decorator.d.ts.map +1 -1
  24. package/dist/mcp/decorators/prompt.decorator.js +2 -1
  25. package/dist/mcp/decorators/prompt.decorator.js.map +1 -1
  26. package/dist/mcp/decorators/public.decorator.js.map +1 -1
  27. package/dist/mcp/decorators/raw-request.decorator.d.ts +2 -0
  28. package/dist/mcp/decorators/raw-request.decorator.d.ts.map +1 -0
  29. package/dist/mcp/decorators/raw-request.decorator.js +6 -0
  30. package/dist/mcp/decorators/raw-request.decorator.js.map +1 -0
  31. package/dist/mcp/decorators/resource-template.decorator.d.ts +1 -1
  32. package/dist/mcp/decorators/resource-template.decorator.d.ts.map +1 -1
  33. package/dist/mcp/decorators/resource-template.decorator.js +2 -1
  34. package/dist/mcp/decorators/resource-template.decorator.js.map +1 -1
  35. package/dist/mcp/decorators/resource.decorator.d.ts +1 -1
  36. package/dist/mcp/decorators/resource.decorator.d.ts.map +1 -1
  37. package/dist/mcp/decorators/resource.decorator.js +2 -1
  38. package/dist/mcp/decorators/resource.decorator.js.map +1 -1
  39. package/dist/mcp/decorators/tool.decorator.d.ts +1 -3
  40. package/dist/mcp/decorators/tool.decorator.d.ts.map +1 -1
  41. package/dist/mcp/decorators/tool.decorator.js +2 -1
  42. package/dist/mcp/decorators/tool.decorator.js.map +1 -1
  43. package/dist/mcp/filters/mcp-exception.filter.d.ts +6 -0
  44. package/dist/mcp/filters/mcp-exception.filter.d.ts.map +1 -0
  45. package/dist/mcp/filters/mcp-exception.filter.js +26 -0
  46. package/dist/mcp/filters/mcp-exception.filter.js.map +1 -0
  47. package/dist/mcp/index.d.ts +11 -7
  48. package/dist/mcp/index.d.ts.map +1 -1
  49. package/dist/mcp/index.js +11 -7
  50. package/dist/mcp/index.js.map +1 -1
  51. package/dist/mcp/interfaces/authenticated-user.interface.d.ts +9 -0
  52. package/dist/mcp/interfaces/authenticated-user.interface.d.ts.map +1 -0
  53. package/dist/{authz/interfaces/request-with-user.js → mcp/interfaces/authenticated-user.interface.js} +1 -1
  54. package/dist/mcp/interfaces/authenticated-user.interface.js.map +1 -0
  55. package/dist/mcp/interfaces/dynamic-prompt.interface.d.ts +1 -1
  56. package/dist/mcp/interfaces/dynamic-prompt.interface.d.ts.map +1 -1
  57. package/dist/mcp/interfaces/dynamic-prompt.interface.js.map +1 -1
  58. package/dist/mcp/interfaces/dynamic-resource.interface.d.ts +1 -1
  59. package/dist/mcp/interfaces/dynamic-resource.interface.d.ts.map +1 -1
  60. package/dist/mcp/interfaces/dynamic-resource.interface.js.map +1 -1
  61. package/dist/mcp/interfaces/dynamic-tool.interface.d.ts +1 -1
  62. package/dist/mcp/interfaces/dynamic-tool.interface.d.ts.map +1 -1
  63. package/dist/mcp/interfaces/dynamic-tool.interface.js.map +1 -1
  64. package/dist/mcp/interfaces/index.d.ts +2 -2
  65. package/dist/mcp/interfaces/index.d.ts.map +1 -1
  66. package/dist/mcp/interfaces/index.js +0 -3
  67. package/dist/mcp/interfaces/index.js.map +1 -1
  68. package/dist/mcp/services/tool-authorization.service.d.ts +7 -5
  69. package/dist/mcp/services/tool-authorization.service.d.ts.map +1 -1
  70. package/dist/mcp/services/tool-authorization.service.js +9 -6
  71. package/dist/mcp/services/tool-authorization.service.js.map +1 -1
  72. package/dist/mcp/transport/mcp-context.d.ts +34 -0
  73. package/dist/mcp/transport/mcp-context.d.ts.map +1 -0
  74. package/dist/mcp/transport/mcp-context.js +74 -0
  75. package/dist/mcp/transport/mcp-context.js.map +1 -0
  76. package/dist/mcp/transport/mcp-http-handler.d.ts +7 -0
  77. package/dist/mcp/transport/mcp-http-handler.d.ts.map +1 -0
  78. package/dist/mcp/transport/mcp-http-handler.js +5 -0
  79. package/dist/mcp/transport/mcp-http-handler.js.map +1 -0
  80. package/dist/mcp/transport/mcp-server-options.interface.d.ts +23 -0
  81. package/dist/mcp/transport/mcp-server-options.interface.d.ts.map +1 -0
  82. package/dist/{authz/providers/oauth-provider.interface.js → mcp/transport/mcp-server-options.interface.js} +1 -1
  83. package/dist/mcp/transport/mcp-server-options.interface.js.map +1 -0
  84. package/dist/mcp/transport/mcp-transport.constants.d.ts +19 -0
  85. package/dist/mcp/transport/mcp-transport.constants.d.ts.map +1 -0
  86. package/dist/mcp/transport/mcp-transport.constants.js +21 -0
  87. package/dist/mcp/transport/mcp-transport.constants.js.map +1 -0
  88. package/dist/mcp/transport/mcp-transport.interface.d.ts +17 -0
  89. package/dist/mcp/transport/mcp-transport.interface.d.ts.map +1 -0
  90. package/dist/{authz/interfaces/oauth-common.interface.js → mcp/transport/mcp-transport.interface.js} +1 -1
  91. package/dist/mcp/transport/mcp-transport.interface.js.map +1 -0
  92. package/dist/mcp/transport/mcp.strategy.d.ts +56 -0
  93. package/dist/mcp/transport/mcp.strategy.d.ts.map +1 -0
  94. package/dist/mcp/transport/mcp.strategy.js +446 -0
  95. package/dist/mcp/transport/mcp.strategy.js.map +1 -0
  96. package/dist/mcp/transport/resource-matcher.d.ts +13 -0
  97. package/dist/mcp/transport/resource-matcher.d.ts.map +1 -0
  98. package/dist/mcp/transport/resource-matcher.js +83 -0
  99. package/dist/mcp/transport/resource-matcher.js.map +1 -0
  100. package/dist/mcp/transport/streamable-http.controller.d.ts +16 -0
  101. package/dist/mcp/transport/streamable-http.controller.d.ts.map +1 -0
  102. package/dist/mcp/transport/streamable-http.controller.js +98 -0
  103. package/dist/mcp/transport/streamable-http.controller.js.map +1 -0
  104. package/dist/mcp/transport/transports/index.d.ts +3 -0
  105. package/dist/mcp/transport/transports/index.d.ts.map +1 -0
  106. package/dist/{authz → mcp/transport/transports}/index.js +2 -10
  107. package/dist/mcp/transport/transports/index.js.map +1 -0
  108. package/dist/mcp/transport/transports/read-body.d.ts +3 -0
  109. package/dist/mcp/transport/transports/read-body.d.ts.map +1 -0
  110. package/dist/mcp/transport/transports/read-body.js +32 -0
  111. package/dist/mcp/transport/transports/read-body.js.map +1 -0
  112. package/dist/mcp/transport/transports/stdio.transport.d.ts +9 -0
  113. package/dist/mcp/transport/transports/stdio.transport.d.ts.map +1 -0
  114. package/dist/mcp/transport/transports/stdio.transport.js +27 -0
  115. package/dist/mcp/transport/transports/stdio.transport.js.map +1 -0
  116. package/dist/mcp/transport/transports/streamable-http.transport.d.ts +33 -0
  117. package/dist/mcp/transport/transports/streamable-http.transport.d.ts.map +1 -0
  118. package/dist/mcp/transport/transports/streamable-http.transport.js +216 -0
  119. package/dist/mcp/transport/transports/streamable-http.transport.js.map +1 -0
  120. package/dist/mcp/utils/mcp-logger.factory.d.ts +6 -2
  121. package/dist/mcp/utils/mcp-logger.factory.d.ts.map +1 -1
  122. package/dist/mcp/utils/mcp-logger.factory.js.map +1 -1
  123. package/package.json +3 -66
  124. package/src/index.ts +0 -1
  125. package/src/mcp/decorators/constants.ts +1 -0
  126. package/src/mcp/decorators/index.ts +3 -1
  127. package/src/mcp/decorators/mcp-controller.decorator.ts +126 -0
  128. package/src/mcp/decorators/mcp-message-pattern.ts +38 -0
  129. package/src/mcp/decorators/prompt.decorator.ts +32 -2
  130. package/src/mcp/decorators/public.decorator.ts +3 -3
  131. package/src/mcp/decorators/raw-request.decorator.ts +32 -0
  132. package/src/mcp/decorators/resource-template.decorator.ts +6 -2
  133. package/src/mcp/decorators/resource.decorator.ts +6 -2
  134. package/src/mcp/decorators/tool.decorator.ts +6 -3
  135. package/src/mcp/filters/mcp-exception.filter.ts +47 -0
  136. package/src/mcp/index.ts +13 -7
  137. package/src/mcp/interfaces/authenticated-user.interface.ts +22 -0
  138. package/src/mcp/interfaces/dynamic-prompt.interface.ts +1 -1
  139. package/src/mcp/interfaces/dynamic-resource.interface.ts +1 -1
  140. package/src/mcp/interfaces/dynamic-tool.interface.ts +2 -2
  141. package/src/mcp/interfaces/index.ts +3 -7
  142. package/src/mcp/services/tool-authorization.service.ts +52 -72
  143. package/src/mcp/transport/mcp-context.ts +138 -0
  144. package/src/mcp/transport/mcp-http-handler.ts +32 -0
  145. package/src/mcp/transport/mcp-server-options.interface.ts +75 -0
  146. package/src/mcp/transport/mcp-transport.constants.ts +99 -0
  147. package/src/mcp/transport/mcp-transport.interface.ts +50 -0
  148. package/src/mcp/transport/mcp.strategy.ts +752 -0
  149. package/src/mcp/transport/resource-matcher.ts +107 -0
  150. package/src/mcp/transport/streamable-http.controller.ts +114 -0
  151. package/src/mcp/transport/transports/index.ts +2 -0
  152. package/src/mcp/transport/transports/read-body.ts +39 -0
  153. package/src/mcp/transport/transports/stdio.transport.ts +35 -0
  154. package/src/mcp/transport/transports/streamable-http.transport.ts +384 -0
  155. package/src/mcp/utils/mcp-logger.factory.spec.ts +8 -22
  156. package/src/mcp/utils/mcp-logger.factory.ts +13 -2
  157. package/dist/authz/guards/jwt-auth.guard.d.ts +0 -19
  158. package/dist/authz/guards/jwt-auth.guard.d.ts.map +0 -1
  159. package/dist/authz/guards/jwt-auth.guard.js +0 -108
  160. package/dist/authz/guards/jwt-auth.guard.js.map +0 -1
  161. package/dist/authz/index.d.ts +0 -11
  162. package/dist/authz/index.d.ts.map +0 -1
  163. package/dist/authz/index.js.map +0 -1
  164. package/dist/authz/interfaces/oauth-common.interface.d.ts +0 -21
  165. package/dist/authz/interfaces/oauth-common.interface.d.ts.map +0 -1
  166. package/dist/authz/interfaces/oauth-common.interface.js.map +0 -1
  167. package/dist/authz/interfaces/request-with-user.d.ts +0 -13
  168. package/dist/authz/interfaces/request-with-user.d.ts.map +0 -1
  169. package/dist/authz/interfaces/request-with-user.js.map +0 -1
  170. package/dist/authz/mcp-oauth.controller.d.ts +0 -81
  171. package/dist/authz/mcp-oauth.controller.d.ts.map +0 -1
  172. package/dist/authz/mcp-oauth.controller.js +0 -540
  173. package/dist/authz/mcp-oauth.controller.js.map +0 -1
  174. package/dist/authz/mcp-oauth.module.d.ts +0 -12
  175. package/dist/authz/mcp-oauth.module.d.ts.map +0 -1
  176. package/dist/authz/mcp-oauth.module.js +0 -271
  177. package/dist/authz/mcp-oauth.module.js.map +0 -1
  178. package/dist/authz/providers/azure-ad.provider.d.ts +0 -3
  179. package/dist/authz/providers/azure-ad.provider.d.ts.map +0 -1
  180. package/dist/authz/providers/azure-ad.provider.js +0 -37
  181. package/dist/authz/providers/azure-ad.provider.js.map +0 -1
  182. package/dist/authz/providers/github.provider.d.ts +0 -3
  183. package/dist/authz/providers/github.provider.d.ts.map +0 -1
  184. package/dist/authz/providers/github.provider.js +0 -24
  185. package/dist/authz/providers/github.provider.js.map +0 -1
  186. package/dist/authz/providers/google.provider.d.ts +0 -3
  187. package/dist/authz/providers/google.provider.d.ts.map +0 -1
  188. package/dist/authz/providers/google.provider.js +0 -25
  189. package/dist/authz/providers/google.provider.js.map +0 -1
  190. package/dist/authz/providers/oauth-provider.interface.d.ts +0 -107
  191. package/dist/authz/providers/oauth-provider.interface.d.ts.map +0 -1
  192. package/dist/authz/providers/oauth-provider.interface.js.map +0 -1
  193. package/dist/authz/services/client.service.d.ts +0 -12
  194. package/dist/authz/services/client.service.d.ts.map +0 -1
  195. package/dist/authz/services/client.service.js +0 -81
  196. package/dist/authz/services/client.service.js.map +0 -1
  197. package/dist/authz/services/jwt-token.service.d.ts +0 -37
  198. package/dist/authz/services/jwt-token.service.d.ts.map +0 -1
  199. package/dist/authz/services/jwt-token.service.js +0 -182
  200. package/dist/authz/services/jwt-token.service.js.map +0 -1
  201. package/dist/authz/services/oauth-strategy.service.d.ts +0 -13
  202. package/dist/authz/services/oauth-strategy.service.d.ts.map +0 -1
  203. package/dist/authz/services/oauth-strategy.service.js +0 -71
  204. package/dist/authz/services/oauth-strategy.service.js.map +0 -1
  205. package/dist/authz/stores/memory-store.service.d.ts +0 -27
  206. package/dist/authz/stores/memory-store.service.d.ts.map +0 -1
  207. package/dist/authz/stores/memory-store.service.js +0 -107
  208. package/dist/authz/stores/memory-store.service.js.map +0 -1
  209. package/dist/authz/stores/oauth-store.interface.d.ts +0 -61
  210. package/dist/authz/stores/oauth-store.interface.d.ts.map +0 -1
  211. package/dist/authz/stores/oauth-store.interface.js +0 -5
  212. package/dist/authz/stores/oauth-store.interface.js.map +0 -1
  213. package/dist/authz/stores/typeorm/constants.d.ts +0 -3
  214. package/dist/authz/stores/typeorm/constants.d.ts.map +0 -1
  215. package/dist/authz/stores/typeorm/constants.js +0 -6
  216. package/dist/authz/stores/typeorm/constants.js.map +0 -1
  217. package/dist/authz/stores/typeorm/entities/authorization-code.entity.d.ts +0 -15
  218. package/dist/authz/stores/typeorm/entities/authorization-code.entity.d.ts.map +0 -1
  219. package/dist/authz/stores/typeorm/entities/authorization-code.entity.js +0 -69
  220. package/dist/authz/stores/typeorm/entities/authorization-code.entity.js.map +0 -1
  221. package/dist/authz/stores/typeorm/entities/index.d.ts +0 -5
  222. package/dist/authz/stores/typeorm/entities/index.d.ts.map +0 -1
  223. package/dist/authz/stores/typeorm/entities/index.js +0 -12
  224. package/dist/authz/stores/typeorm/entities/index.js.map +0 -1
  225. package/dist/authz/stores/typeorm/entities/oauth-client.entity.d.ts +0 -17
  226. package/dist/authz/stores/typeorm/entities/oauth-client.entity.d.ts.map +0 -1
  227. package/dist/authz/stores/typeorm/entities/oauth-client.entity.js +0 -77
  228. package/dist/authz/stores/typeorm/entities/oauth-client.entity.js.map +0 -1
  229. package/dist/authz/stores/typeorm/entities/oauth-session.entity.d.ts +0 -14
  230. package/dist/authz/stores/typeorm/entities/oauth-session.entity.d.ts.map +0 -1
  231. package/dist/authz/stores/typeorm/entities/oauth-session.entity.js +0 -65
  232. package/dist/authz/stores/typeorm/entities/oauth-session.entity.js.map +0 -1
  233. package/dist/authz/stores/typeorm/entities/user-profile.entity.d.ts +0 -13
  234. package/dist/authz/stores/typeorm/entities/user-profile.entity.d.ts.map +0 -1
  235. package/dist/authz/stores/typeorm/entities/user-profile.entity.js +0 -62
  236. package/dist/authz/stores/typeorm/entities/user-profile.entity.js.map +0 -1
  237. package/dist/authz/stores/typeorm/typeorm-store.service.d.ts +0 -28
  238. package/dist/authz/stores/typeorm/typeorm-store.service.d.ts.map +0 -1
  239. package/dist/authz/stores/typeorm/typeorm-store.service.js +0 -138
  240. package/dist/authz/stores/typeorm/typeorm-store.service.js.map +0 -1
  241. package/dist/mcp/constants/feature-registration.constants.d.ts +0 -7
  242. package/dist/mcp/constants/feature-registration.constants.d.ts.map +0 -1
  243. package/dist/mcp/constants/feature-registration.constants.js +0 -5
  244. package/dist/mcp/constants/feature-registration.constants.js.map +0 -1
  245. package/dist/mcp/decorators/tool-guards.decorator.d.ts +0 -12
  246. package/dist/mcp/decorators/tool-guards.decorator.d.ts.map +0 -1
  247. package/dist/mcp/decorators/tool-guards.decorator.js +0 -13
  248. package/dist/mcp/decorators/tool-guards.decorator.js.map +0 -1
  249. package/dist/mcp/interfaces/mcp-options.interface.d.ts +0 -53
  250. package/dist/mcp/interfaces/mcp-options.interface.d.ts.map +0 -1
  251. package/dist/mcp/interfaces/mcp-options.interface.js +0 -10
  252. package/dist/mcp/interfaces/mcp-options.interface.js.map +0 -1
  253. package/dist/mcp/mcp.module.d.ts +0 -15
  254. package/dist/mcp/mcp.module.d.ts.map +0 -1
  255. package/dist/mcp/mcp.module.js +0 -248
  256. package/dist/mcp/mcp.module.js.map +0 -1
  257. package/dist/mcp/services/handlers/mcp-handler.base.d.ts +0 -117
  258. package/dist/mcp/services/handlers/mcp-handler.base.d.ts.map +0 -1
  259. package/dist/mcp/services/handlers/mcp-handler.base.js +0 -125
  260. package/dist/mcp/services/handlers/mcp-handler.base.js.map +0 -1
  261. package/dist/mcp/services/handlers/mcp-prompts.handler.d.ts +0 -12
  262. package/dist/mcp/services/handlers/mcp-prompts.handler.d.ts.map +0 -1
  263. package/dist/mcp/services/handlers/mcp-prompts.handler.js +0 -98
  264. package/dist/mcp/services/handlers/mcp-prompts.handler.js.map +0 -1
  265. package/dist/mcp/services/handlers/mcp-resources.handler.d.ts +0 -13
  266. package/dist/mcp/services/handlers/mcp-resources.handler.d.ts.map +0 -1
  267. package/dist/mcp/services/handlers/mcp-resources.handler.js +0 -117
  268. package/dist/mcp/services/handlers/mcp-resources.handler.js.map +0 -1
  269. package/dist/mcp/services/handlers/mcp-tools.handler.d.ts +0 -22
  270. package/dist/mcp/services/handlers/mcp-tools.handler.d.ts.map +0 -1
  271. package/dist/mcp/services/handlers/mcp-tools.handler.js +0 -258
  272. package/dist/mcp/services/handlers/mcp-tools.handler.js.map +0 -1
  273. package/dist/mcp/services/mcp-dynamic-registry.service.d.ts +0 -26
  274. package/dist/mcp/services/mcp-dynamic-registry.service.d.ts.map +0 -1
  275. package/dist/mcp/services/mcp-dynamic-registry.service.js +0 -133
  276. package/dist/mcp/services/mcp-dynamic-registry.service.js.map +0 -1
  277. package/dist/mcp/services/mcp-executor.service.d.ts +0 -15
  278. package/dist/mcp/services/mcp-executor.service.d.ts.map +0 -1
  279. package/dist/mcp/services/mcp-executor.service.js +0 -47
  280. package/dist/mcp/services/mcp-executor.service.js.map +0 -1
  281. package/dist/mcp/services/mcp-registry-discovery.service.d.ts +0 -63
  282. package/dist/mcp/services/mcp-registry-discovery.service.d.ts.map +0 -1
  283. package/dist/mcp/services/mcp-registry-discovery.service.js +0 -397
  284. package/dist/mcp/services/mcp-registry-discovery.service.js.map +0 -1
  285. package/dist/mcp/services/mcp-sse.service.d.ts +0 -20
  286. package/dist/mcp/services/mcp-sse.service.d.ts.map +0 -1
  287. package/dist/mcp/services/mcp-sse.service.js +0 -91
  288. package/dist/mcp/services/mcp-sse.service.js.map +0 -1
  289. package/dist/mcp/services/mcp-streamable-http.service.d.ts +0 -32
  290. package/dist/mcp/services/mcp-streamable-http.service.d.ts.map +0 -1
  291. package/dist/mcp/services/mcp-streamable-http.service.js +0 -327
  292. package/dist/mcp/services/mcp-streamable-http.service.js.map +0 -1
  293. package/dist/mcp/services/sse-ping.service.d.ts +0 -23
  294. package/dist/mcp/services/sse-ping.service.d.ts.map +0 -1
  295. package/dist/mcp/services/sse-ping.service.js +0 -99
  296. package/dist/mcp/services/sse-ping.service.js.map +0 -1
  297. package/dist/mcp/transport/sse.controller.factory.d.ts +0 -14
  298. package/dist/mcp/transport/sse.controller.factory.d.ts.map +0 -1
  299. package/dist/mcp/transport/sse.controller.factory.js +0 -67
  300. package/dist/mcp/transport/sse.controller.factory.js.map +0 -1
  301. package/dist/mcp/transport/stdio.service.d.ts +0 -14
  302. package/dist/mcp/transport/stdio.service.d.ts.map +0 -1
  303. package/dist/mcp/transport/stdio.service.js +0 -66
  304. package/dist/mcp/transport/stdio.service.js.map +0 -1
  305. package/dist/mcp/transport/streamable-http.controller.factory.d.ts +0 -14
  306. package/dist/mcp/transport/streamable-http.controller.factory.d.ts.map +0 -1
  307. package/dist/mcp/transport/streamable-http.controller.factory.js +0 -74
  308. package/dist/mcp/transport/streamable-http.controller.factory.js.map +0 -1
  309. package/dist/mcp/utils/capabilities-builder.d.ts +0 -5
  310. package/dist/mcp/utils/capabilities-builder.d.ts.map +0 -1
  311. package/dist/mcp/utils/capabilities-builder.js +0 -25
  312. package/dist/mcp/utils/capabilities-builder.js.map +0 -1
  313. package/dist/mcp/utils/mcp-server.factory.d.ts +0 -6
  314. package/dist/mcp/utils/mcp-server.factory.d.ts.map +0 -1
  315. package/dist/mcp/utils/mcp-server.factory.js +0 -22
  316. package/dist/mcp/utils/mcp-server.factory.js.map +0 -1
  317. package/src/authz/guards/jwt-auth.guard.ts +0 -127
  318. package/src/authz/index.ts +0 -10
  319. package/src/authz/interfaces/oauth-common.interface.ts +0 -21
  320. package/src/authz/interfaces/request-with-user.ts +0 -16
  321. package/src/authz/mcp-oauth.controller.ts +0 -860
  322. package/src/authz/mcp-oauth.module.ts +0 -384
  323. package/src/authz/providers/azure-ad.provider.ts +0 -40
  324. package/src/authz/providers/github.provider.ts +0 -22
  325. package/src/authz/providers/google.provider.ts +0 -23
  326. package/src/authz/providers/oauth-provider.interface.ts +0 -147
  327. package/src/authz/services/client.service.ts +0 -125
  328. package/src/authz/services/jwt-token.service.spec.ts +0 -67
  329. package/src/authz/services/jwt-token.service.ts +0 -188
  330. package/src/authz/services/oauth-strategy.service.ts +0 -64
  331. package/src/authz/stores/memory-store.service.spec.ts +0 -475
  332. package/src/authz/stores/memory-store.service.ts +0 -141
  333. package/src/authz/stores/oauth-store.interface.ts +0 -131
  334. package/src/authz/stores/typeorm/README.md +0 -140
  335. package/src/authz/stores/typeorm/constants.ts +0 -6
  336. package/src/authz/stores/typeorm/entities/authorization-code.entity.ts +0 -41
  337. package/src/authz/stores/typeorm/entities/index.ts +0 -4
  338. package/src/authz/stores/typeorm/entities/oauth-client.entity.ts +0 -53
  339. package/src/authz/stores/typeorm/entities/oauth-session.entity.ts +0 -38
  340. package/src/authz/stores/typeorm/entities/user-profile.entity.ts +0 -46
  341. package/src/authz/stores/typeorm/typeorm-store.service.spec.ts +0 -494
  342. package/src/authz/stores/typeorm/typeorm-store.service.ts +0 -165
  343. package/src/mcp/constants/feature-registration.constants.ts +0 -24
  344. package/src/mcp/decorators/tool-guards.decorator.ts +0 -82
  345. package/src/mcp/interfaces/mcp-options.interface.ts +0 -95
  346. package/src/mcp/mcp.module.ts +0 -349
  347. package/src/mcp/services/handlers/mcp-handler.base.ts +0 -203
  348. package/src/mcp/services/handlers/mcp-prompts.handler.ts +0 -143
  349. package/src/mcp/services/handlers/mcp-resources.handler.ts +0 -183
  350. package/src/mcp/services/handlers/mcp-tools.handler.spec.ts +0 -41
  351. package/src/mcp/services/handlers/mcp-tools.handler.ts +0 -436
  352. package/src/mcp/services/mcp-dynamic-registry.service.ts +0 -236
  353. package/src/mcp/services/mcp-executor.service.ts +0 -64
  354. package/src/mcp/services/mcp-registry-discovery.service.spec.ts +0 -306
  355. package/src/mcp/services/mcp-registry-discovery.service.ts +0 -849
  356. package/src/mcp/services/mcp-sse.service.ts +0 -124
  357. package/src/mcp/services/mcp-streamable-http.service.ts +0 -472
  358. package/src/mcp/services/sse-ping.service.ts +0 -144
  359. package/src/mcp/transport/custom-decorator.spec.ts +0 -75
  360. package/src/mcp/transport/sse.controller.factory.ts +0 -84
  361. package/src/mcp/transport/stdio.service.ts +0 -75
  362. package/src/mcp/transport/streamable-http.controller.factory.ts +0 -80
  363. package/src/mcp/utils/capabilities-builder.ts +0 -43
  364. package/src/mcp/utils/mcp-server.factory.ts +0 -33
@@ -0,0 +1,107 @@
1
+ import { match } from 'path-to-regexp';
2
+
3
+ /** Strips the scheme (`mcp://foo` -> `foo`). */
4
+ function stripScheme(uri: string): string {
5
+ return uri.includes('://') ? uri.split('://')[1] : uri;
6
+ }
7
+
8
+ /**
9
+ * RFC 6570 template -> path-to-regexp (v8) path:
10
+ * - drop the `{?query}` form,
11
+ * - turn a catch-all `{path*}` into a wildcard `*path` (matches one or more
12
+ * segments across `/`),
13
+ * - turn a single `{p}` into `:p` (one segment).
14
+ *
15
+ * The catch-all rule MUST run before the single-param rule: `{(\w+)}` can't
16
+ * match `{path*}` (the `*` sits between `\w+` and `}`), which is the bug that
17
+ * previously left `{path*}` untouched so it never matched.
18
+ */
19
+ function convertTemplate(template: string): string {
20
+ if (!template) return template;
21
+ return template
22
+ .replace(/\{\?[^}]+\}/g, '')
23
+ .replace(/\{(\w+)\*\}/g, '*$1')
24
+ .replace(/\{(\w+)\}/g, ':$1');
25
+ }
26
+
27
+ /**
28
+ * path-to-regexp v8 returns wildcard (`*path`) params as an array of segments,
29
+ * while named (`:id`) params come back as strings. Join wildcard arrays with
30
+ * `/` so a `{path*}` template hands the handler a single string
31
+ * (e.g. `docs/readme.md`), preserving the documented contract.
32
+ */
33
+ function flattenParams(
34
+ params: Partial<Record<string, string | string[]>>,
35
+ ): Record<string, string> {
36
+ const out: Record<string, string> = {};
37
+ for (const [key, value] of Object.entries(params)) {
38
+ if (value === undefined) continue;
39
+ out[key] = Array.isArray(value) ? value.join('/') : value;
40
+ }
41
+ return out;
42
+ }
43
+
44
+ function extractTemplateQueryParams(template: string): string[] {
45
+ const m = template.match(/\{\?([^}]+)\}/);
46
+ return m ? m[1].split(',').map((p) => p.trim()) : [];
47
+ }
48
+
49
+ function parseQueryString(uri: string): Record<string, string> {
50
+ const i = uri.indexOf('?');
51
+ if (i === -1) return {};
52
+ const params: Record<string, string> = {};
53
+ for (const pair of uri.substring(i + 1).split('&')) {
54
+ const [k, v] = pair.split('=');
55
+ if (k) params[decodeURIComponent(k)] = v ? decodeURIComponent(v) : '';
56
+ }
57
+ return params;
58
+ }
59
+
60
+ function stripQueryString(uri: string): string {
61
+ const i = uri.indexOf('?');
62
+ return i === -1 ? uri : uri.substring(0, i);
63
+ }
64
+
65
+ /** Finds a static resource whose URI matches `inputUri`, extracting any path params. */
66
+ export function matchResourceByUri<T extends { uri?: string }>(
67
+ resources: T[],
68
+ inputUri: string,
69
+ ): { resource: T; params: Record<string, string> } | undefined {
70
+ const input = stripScheme(inputUri);
71
+ for (const resource of resources) {
72
+ if (!resource.uri) continue;
73
+ const matcher = match(convertTemplate(stripScheme(resource.uri)), {
74
+ decode: decodeURIComponent,
75
+ });
76
+ const result = matcher(input);
77
+ if (result) {
78
+ return { resource, params: flattenParams(result.params) };
79
+ }
80
+ }
81
+ return undefined;
82
+ }
83
+
84
+ /** Finds a resource template matching `inputUri`, extracting path + declared query params. */
85
+ export function matchResourceTemplateByUri<T extends { uriTemplate?: string }>(
86
+ templates: T[],
87
+ inputUri: string,
88
+ ): { template: T; params: Record<string, string> } | undefined {
89
+ const input = stripQueryString(stripScheme(inputUri));
90
+ const inputQuery = parseQueryString(inputUri);
91
+ for (const template of templates) {
92
+ if (!template.uriTemplate) continue;
93
+ const matcher = match(convertTemplate(stripScheme(template.uriTemplate)), {
94
+ decode: decodeURIComponent,
95
+ });
96
+ const result = matcher(input);
97
+ if (result) {
98
+ const params = flattenParams(result.params);
99
+ const query: Record<string, string> = {};
100
+ for (const name of extractTemplateQueryParams(template.uriTemplate)) {
101
+ if (inputQuery[name] !== undefined) query[name] = inputQuery[name];
102
+ }
103
+ return { template, params: { ...params, ...query } };
104
+ }
105
+ }
106
+ return undefined;
107
+ }
@@ -0,0 +1,114 @@
1
+ import { Delete, Get, Inject, Post, Req, Res } from '@nestjs/common';
2
+ import { MCP_HTTP_HANDLER, type McpHttpHandler } from './mcp-http-handler';
3
+
4
+ /** Anything that can hand out MCP HTTP verb handlers — i.e. a transport. */
5
+ export interface McpHttpHandlerSource {
6
+ readonly httpHandlers: McpHttpHandler;
7
+ }
8
+
9
+ /**
10
+ * Build a base controller bound DIRECTLY to a specific transport — the
11
+ * legible way to wire a bring-your-own MCP controller.
12
+ *
13
+ * Instead of providing handlers under a DI token and hoping the right one
14
+ * resolves (which gets confusing with multiple servers), the controller simply
15
+ * names the transport it serves. The binding is a concrete reference you can
16
+ * click through to:
17
+ *
18
+ * ```ts
19
+ * @Controller('weather/mcp')
20
+ * @UseGuards(WeatherAuthGuard)
21
+ * export class WeatherMcpController extends McpHttpControllerFor(weatherTransport) {}
22
+ * ```
23
+ *
24
+ * No `MCP_HTTP_HANDLER` provider, no module-local resolution to reason about: a
25
+ * reader sees `weatherTransport`, jumps to where it's declared, and finds it in
26
+ * `weatherStrategy({ server: 'weather' })` next to the weather tools. One hop.
27
+ *
28
+ * Reading `source.httpHandlers` here (at class-definition / import time) also
29
+ * marks the route as claimed, so the transport auto-disables its own self-mount.
30
+ *
31
+ * You still own the subclass decorators — `@Controller(path)`, `@UseGuards`,
32
+ * `@UseInterceptors`, `@Version`, etc. all compose normally; the library only
33
+ * owns the `POST`/`GET`/`DELETE` wiring.
34
+ */
35
+ export function McpHttpControllerFor(source: McpHttpHandlerSource) {
36
+ const handlers = source.httpHandlers;
37
+
38
+ abstract class BoundMcpHttpController {
39
+ @Post()
40
+ post(@Req() req: unknown, @Res() res: unknown): Promise<void> | void {
41
+ return handlers.handlePost(req, res);
42
+ }
43
+
44
+ @Get()
45
+ get(@Req() req: unknown, @Res() res: unknown): Promise<void> | void {
46
+ return handlers.handleGet(req, res);
47
+ }
48
+
49
+ @Delete()
50
+ delete(@Req() req: unknown, @Res() res: unknown): Promise<void> | void {
51
+ return handlers.handleDelete(req, res);
52
+ }
53
+ }
54
+
55
+ return BoundMcpHttpController;
56
+ }
57
+
58
+ /**
59
+ * Abstract base controller for the streamable-HTTP MCP endpoint.
60
+ *
61
+ * Extend it to mount the MCP route as a real NestJS controller — so guards,
62
+ * interceptors, exception filters and versioning apply the normal Nest way,
63
+ * while the library keeps ownership of the `POST`/`GET`/`DELETE` wiring
64
+ * (session handling, SSE streaming, raw-body reading). You never reimplement the
65
+ * verbs; you just decorate your subclass:
66
+ *
67
+ * ```ts
68
+ * @Controller('mcp')
69
+ * @UseGuards(MyAuthGuard) // ← authenticate the whole MCP surface, once
70
+ * export class McpController extends StreamableHttpController {}
71
+ * ```
72
+ *
73
+ * Wiring is a single line — provide the transport's handlers under
74
+ * {@link MCP_HTTP_HANDLER} so this base can inject them:
75
+ *
76
+ * ```ts
77
+ * { provide: MCP_HTTP_HANDLER, useValue: mcpTransport.httpHandlers }
78
+ * ```
79
+ *
80
+ * Reading `httpHandlers` there also auto-disables the transport's own
81
+ * self-mount, so you do NOT need `{ mount: false }` — your controller owns the
82
+ * route and there is no double-registration. (Pass `mount` explicitly only to
83
+ * override that.) The path lives on YOUR `@Controller(...)` decorator, not on
84
+ * the transport.
85
+ *
86
+ * Implementation notes:
87
+ * - `@Controller()` must be on the concrete subclass; Nest registers the route
88
+ * handlers it finds on the prototype chain, including these inherited ones.
89
+ * - The handler is injected via a property (not the constructor) so subclasses
90
+ * need no constructor and no `super(...)` call — and so it survives NestJS's
91
+ * inherited-constructor-metadata quirks.
92
+ * - `@Res()` puts Nest in manual-response mode: the SDK transport writes the
93
+ * response (and SSE stream) directly, so Nest must not serialize a return
94
+ * value.
95
+ */
96
+ export abstract class StreamableHttpController {
97
+ @Inject(MCP_HTTP_HANDLER)
98
+ protected readonly mcpHandler!: McpHttpHandler;
99
+
100
+ @Post()
101
+ post(@Req() req: unknown, @Res() res: unknown): Promise<void> | void {
102
+ return this.mcpHandler.handlePost(req, res);
103
+ }
104
+
105
+ @Get()
106
+ get(@Req() req: unknown, @Res() res: unknown): Promise<void> | void {
107
+ return this.mcpHandler.handleGet(req, res);
108
+ }
109
+
110
+ @Delete()
111
+ delete(@Req() req: unknown, @Res() res: unknown): Promise<void> | void {
112
+ return this.mcpHandler.handleDelete(req, res);
113
+ }
114
+ }
@@ -0,0 +1,2 @@
1
+ export * from './stdio.transport';
2
+ export * from './streamable-http.transport';
@@ -0,0 +1,39 @@
1
+ import { HttpRequest } from '../../interfaces/http-adapter.interface';
2
+
3
+ /**
4
+ * Resolves the JSON request body for an MCP HTTP request.
5
+ *
6
+ * Prefers an already-parsed body (`adaptedReq.body`) when a framework body-parser
7
+ * ran (e.g. Fastify parses before route handlers). Otherwise reads the raw Node
8
+ * stream — the case for Express, where MCP routes are mounted before NestJS adds
9
+ * its body-parser middleware, so `req.body` is undefined and the stream is intact.
10
+ * Reading once here also lets the transport inspect the payload (e.g. to detect an
11
+ * `initialize` request) before handing off to the SDK.
12
+ */
13
+ export async function readJsonBody(adaptedReq: HttpRequest): Promise<unknown> {
14
+ if (adaptedReq.body !== undefined) {
15
+ return adaptedReq.body;
16
+ }
17
+ const rawReq = adaptedReq.raw;
18
+ if (rawReq?.body !== undefined) {
19
+ return rawReq.body;
20
+ }
21
+ return new Promise((resolve) => {
22
+ let data = '';
23
+ rawReq.on('data', (chunk: Buffer | string) => {
24
+ data += chunk.toString();
25
+ });
26
+ rawReq.on('end', () => {
27
+ if (!data) {
28
+ resolve(undefined);
29
+ return;
30
+ }
31
+ try {
32
+ resolve(JSON.parse(data));
33
+ } catch {
34
+ resolve(undefined);
35
+ }
36
+ });
37
+ rawReq.on('error', () => resolve(undefined));
38
+ });
39
+ }
@@ -0,0 +1,35 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
3
+ import { McpTransport, McpTransportContext } from '../mcp-transport.interface';
4
+
5
+ /**
6
+ * stdio transport. Starts a single long-lived MCP server bound to the process'
7
+ * stdin/stdout. Intended for CLI-style MCP servers launched by an MCP client.
8
+ *
9
+ * No HTTP adapter is required. As a persistent, session-aware connection, stdio
10
+ * supports progress notifications and server-side logging.
11
+ */
12
+ export class StdioTransport implements McpTransport {
13
+ readonly kind = 'stdio' as const;
14
+
15
+ private server?: McpServer;
16
+ private transport?: StdioServerTransport;
17
+
18
+ async start(ctx: McpTransportContext): Promise<void> {
19
+ this.server = ctx.createServer();
20
+ ctx.bindRequestHandlers(this.server, {
21
+ transport: this.kind,
22
+ stateless: false,
23
+ });
24
+ this.transport = new StdioServerTransport();
25
+ await this.server.connect(this.transport);
26
+ ctx.logger.log('MCP stdio transport started');
27
+ }
28
+
29
+ async close(): Promise<void> {
30
+ await this.transport?.close();
31
+ await this.server?.close();
32
+ this.transport = undefined;
33
+ this.server = undefined;
34
+ }
35
+ }
@@ -0,0 +1,384 @@
1
+ import { randomUUID } from 'crypto';
2
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
3
+ import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
4
+ import { HttpAdapterFactory } from '../../adapters/http-adapter.factory';
5
+ import { HttpResponse } from '../../interfaces/http-adapter.interface';
6
+ import { McpTransport, McpTransportContext } from '../mcp-transport.interface';
7
+ import type { McpHttpHandler } from '../mcp-http-handler';
8
+ import { readJsonBody } from './read-body';
9
+
10
+ export interface StreamableHttpTransportOptions {
11
+ /**
12
+ * Path of the transport's **self-mounted** route.
13
+ *
14
+ * This ONLY applies when the transport self-mounts (no controller owns the
15
+ * route). A self-mounted route is registered directly on the HTTP adapter,
16
+ * OUTSIDE Nest's routing pipeline — so it does not pick up
17
+ * `app.setGlobalPrefix(...)`, URI versioning, guards, or interceptors. Use
18
+ * `endpoint` for a trivial path change on a no-auth server.
19
+ *
20
+ * When you bring your own controller, the path comes from your
21
+ * `@Controller(...)` decorator (and global prefix / versioning apply normally)
22
+ * — `endpoint` is ignored. The transport logs a warning if you set it anyway.
23
+ *
24
+ * @default '/mcp'
25
+ */
26
+ endpoint?: string;
27
+ /**
28
+ * Enable session management (a long-lived MCP server per session, identified
29
+ * by the `mcp-session-id` header, with `GET`/`DELETE` support for SSE streams
30
+ * and session teardown).
31
+ *
32
+ * Left off (the default), the transport is **stateless**: every request is
33
+ * self-contained, a fresh server is created and torn down per request, and
34
+ * `GET`/`DELETE` return `405`. Stateless is the simplest mode and the right
35
+ * default for most servers; turn this on only when you need server-initiated
36
+ * streaming/notifications tied to a session.
37
+ *
38
+ * @default false (stateless)
39
+ */
40
+ statefulMode?: boolean;
41
+ /**
42
+ * Return a single JSON response instead of opening an SSE stream.
43
+ *
44
+ * When unset, this **follows the session mode**: `true` in stateless mode (so
45
+ * a plain POST gets a JSON reply with no stream to manage) and `false` in
46
+ * stateful mode (SSE, so server-initiated messages can flow). Set it
47
+ * explicitly to override that pairing.
48
+ *
49
+ * @default `!statefulMode` (JSON when stateless, SSE when stateful)
50
+ */
51
+ enableJsonResponse?: boolean;
52
+ /** Custom session id generator (stateful mode). */
53
+ sessionIdGenerator?: () => string;
54
+ /**
55
+ * Whether the transport mounts its own `POST`/`GET`/`DELETE` routes on the
56
+ * Nest HTTP adapter.
57
+ *
58
+ * Leave it unset (the default) for **auto-detection**: the transport
59
+ * self-mounts UNLESS something has read {@link httpHandlers} — which happens
60
+ * exactly when you wire a bring-your-own `@Controller` (e.g. via
61
+ * `{ provide: MCP_HTTP_HANDLER, useValue: transport.httpHandlers }`). So
62
+ * providing a controller automatically suppresses self-mounting; doing
63
+ * nothing keeps the zero-config self-mount. This read happens at module
64
+ * definition time, before the transport starts, so the timing is reliable.
65
+ *
66
+ * Set it explicitly to override the heuristic:
67
+ * - `true`: always self-mount (bypasses the Nest pipeline — no guards).
68
+ * - `false`: never self-mount (you own the route via a controller).
69
+ *
70
+ * @default undefined (auto: self-mount unless `httpHandlers` was accessed)
71
+ */
72
+ mount?: boolean;
73
+ }
74
+
75
+ /**
76
+ * Streamable-HTTP transport. Mounts `POST`/`GET`/`DELETE` on the Nest HTTP server
77
+ * and delegates to the MCP SDK `StreamableHTTPServerTransport`. Supports both the
78
+ * stateless (one server per request) and stateful (session-managed) modes.
79
+ */
80
+ export class StreamableHttpTransport implements McpTransport {
81
+ readonly kind = 'streamable-http' as const;
82
+
83
+ private readonly endpoint: string;
84
+ private readonly statefulMode: boolean;
85
+ private readonly enableJsonResponse: boolean;
86
+ private readonly sessionIdGenerator: () => string;
87
+ /** Whether `endpoint` was set explicitly (vs defaulted) — for the ignored-option warning. */
88
+ private readonly endpointExplicit: boolean;
89
+ /** Explicit `mount` override; `undefined` means auto-detect. */
90
+ private readonly mountOption?: boolean;
91
+ /** Set the first time {@link httpHandlers} is read — implies a BYO controller. */
92
+ private handlersClaimed = false;
93
+
94
+ private readonly transports: Record<string, StreamableHTTPServerTransport> =
95
+ {};
96
+ private readonly servers: Record<string, McpServer> = {};
97
+ private ctx?: McpTransportContext;
98
+
99
+ constructor(options: StreamableHttpTransportOptions = {}) {
100
+ this.endpoint = ensureLeadingSlash(options.endpoint ?? 'mcp');
101
+ this.endpointExplicit = options.endpoint !== undefined;
102
+ this.statefulMode = options.statefulMode ?? false;
103
+ // Default follows the session mode: JSON in stateless, SSE in stateful.
104
+ this.enableJsonResponse =
105
+ options.enableJsonResponse ?? !this.statefulMode;
106
+ this.sessionIdGenerator =
107
+ options.sessionIdGenerator ?? (() => randomUUID());
108
+ this.mountOption = options.mount;
109
+ }
110
+
111
+ /**
112
+ * The HTTP verb handlers, for bring-your-own-controller setups. Provide this
113
+ * under `MCP_HTTP_HANDLER` and delegate to it from a `@Controller` (see
114
+ * {@link StreamableHttpController}). The returned functions are bound to this
115
+ * transport and read their context lazily, so it is safe to grab this getter
116
+ * at module-construction time — before `start()` has run.
117
+ *
118
+ * Reading this getter also marks the route as claimed, so the transport
119
+ * auto-disables its own self-mount (unless `mount` was set explicitly). That
120
+ * is how `{ provide: MCP_HTTP_HANDLER, useValue: transport.httpHandlers }`
121
+ * suppresses self-mounting without any extra flag.
122
+ */
123
+ get httpHandlers(): McpHttpHandler {
124
+ this.handlersClaimed = true;
125
+ return {
126
+ handlePost: (req: unknown, res: unknown) => this.handlePost(req, res),
127
+ handleGet: (req: unknown, res: unknown) => this.handleGet(req, res),
128
+ handleDelete: (req: unknown, res: unknown) => this.handleDelete(req, res),
129
+ };
130
+ }
131
+
132
+ start(ctx: McpTransportContext): void {
133
+ // The context (server factory, request-handler binding, logger) is always
134
+ // needed — the handlers read it lazily whether we self-mount or a user
135
+ // controller calls them.
136
+ this.ctx = ctx;
137
+
138
+ // Auto-detect: self-mount unless a controller claimed the route by reading
139
+ // `httpHandlers`. An explicit `mount` option overrides the heuristic.
140
+ const shouldMount = this.mountOption ?? !this.handlersClaimed;
141
+
142
+ if (!shouldMount) {
143
+ // The path now comes from the user's @Controller(...), so a self-mount
144
+ // `endpoint` would be silently ignored. Don't let that pass quietly.
145
+ if (this.endpointExplicit) {
146
+ ctx.logger.warn(
147
+ `StreamableHttpTransport: \`endpoint: '${this.endpoint}'\` is ignored because a controller owns the route. Set the path on your @Controller(...) decorator instead (it also picks up global prefix and versioning).`,
148
+ );
149
+ }
150
+ ctx.logger.log(
151
+ `MCP streamable-http transport ready (${this.statefulMode ? 'stateful' : 'stateless'}, self-mount disabled — a controller owns the route)`,
152
+ );
153
+ return;
154
+ }
155
+
156
+ if (!ctx.httpAdapter) {
157
+ throw new Error(
158
+ 'StreamableHttpTransport requires an HTTP adapter to self-mount. Pass it via new McpStrategy({ httpAdapter }) or strategy.setHttpAdapter(app.getHttpAdapter()) — or mount your own controller (provide MCP_HTTP_HANDLER with transport.httpHandlers).',
159
+ );
160
+ }
161
+ const adapter = ctx.httpAdapter as unknown as {
162
+ post(path: string, handler: (req: any, res: any) => unknown): unknown;
163
+ get(path: string, handler: (req: any, res: any) => unknown): unknown;
164
+ delete(path: string, handler: (req: any, res: any) => unknown): unknown;
165
+ };
166
+
167
+ adapter.post(this.endpoint, (req, res) => this.handlePost(req, res));
168
+ adapter.get(this.endpoint, (req, res) => this.handleGet(req, res));
169
+ adapter.delete(this.endpoint, (req, res) => this.handleDelete(req, res));
170
+
171
+ ctx.logger.log(
172
+ `MCP streamable-http transport mounted at ${this.endpoint} (${this.statefulMode ? 'stateful' : 'stateless'})`,
173
+ );
174
+ }
175
+
176
+ async close(): Promise<void> {
177
+ for (const sessionId of Object.keys(this.transports)) {
178
+ await this.cleanupSession(sessionId);
179
+ }
180
+ }
181
+
182
+ private async handlePost(req: any, res: any): Promise<void> {
183
+ const adapter = HttpAdapterFactory.getAdapter(req, res);
184
+ const adaptedReq = adapter.adaptRequest(req);
185
+ const adaptedRes = adapter.adaptResponse(res);
186
+ const body = await readJsonBody(adaptedReq);
187
+
188
+ try {
189
+ if (this.statefulMode) {
190
+ await this.handleStateful(adaptedReq, adaptedRes, body);
191
+ } else {
192
+ await this.handleStateless(adaptedReq, adaptedRes, body);
193
+ }
194
+ } catch (error) {
195
+ this.ctx!.logger.error('Error handling MCP request', error as Error);
196
+ if (!adaptedRes.headersSent) {
197
+ adaptedRes.status(500).json({
198
+ jsonrpc: '2.0',
199
+ error: { code: -32603, message: 'Internal server error' },
200
+ id: null,
201
+ });
202
+ }
203
+ }
204
+ }
205
+
206
+ private async handleStateless(
207
+ req: ReturnType<
208
+ ReturnType<typeof HttpAdapterFactory.getAdapter>['adaptRequest']
209
+ >,
210
+ res: HttpResponse,
211
+ body: unknown,
212
+ ): Promise<void> {
213
+ const transport = new StreamableHTTPServerTransport({
214
+ sessionIdGenerator: undefined,
215
+ enableJsonResponse: this.enableJsonResponse,
216
+ });
217
+ const server = this.ctx!.createServer();
218
+ await server.connect(transport);
219
+ this.ctx!.bindRequestHandlers(
220
+ server,
221
+ { transport: this.kind, stateless: true },
222
+ req.raw,
223
+ );
224
+
225
+ res.raw.on('finish', () => {
226
+ void transport.close();
227
+ void server.close();
228
+ });
229
+
230
+ await transport.handleRequest(req.raw, res.raw, body);
231
+ }
232
+
233
+ private async handleStateful(
234
+ req: ReturnType<
235
+ ReturnType<typeof HttpAdapterFactory.getAdapter>['adaptRequest']
236
+ >,
237
+ res: HttpResponse,
238
+ body: unknown,
239
+ ): Promise<void> {
240
+ const sessionId = req.headers['mcp-session-id'] as string | undefined;
241
+
242
+ if (!sessionId && isInitializeRequest(body)) {
243
+ const server = this.ctx!.createServer();
244
+ const transport = new StreamableHTTPServerTransport({
245
+ sessionIdGenerator: this.sessionIdGenerator,
246
+ enableJsonResponse: this.enableJsonResponse,
247
+ onsessioninitialized: (sid: string) => {
248
+ this.transports[sid] = transport;
249
+ this.servers[sid] = server;
250
+ },
251
+ onsessionclosed: (sid: string) => {
252
+ void this.cleanupSession(sid);
253
+ },
254
+ });
255
+ await server.connect(transport);
256
+ this.ctx!.bindRequestHandlers(
257
+ server,
258
+ { transport: this.kind, stateless: false },
259
+ req.raw,
260
+ );
261
+ await transport.handleRequest(req.raw, res.raw, body);
262
+ return;
263
+ }
264
+
265
+ if (sessionId) {
266
+ const transport = this.transports[sessionId];
267
+ const server = this.servers[sessionId];
268
+ if (!transport || !server) {
269
+ res.status(404).json({
270
+ jsonrpc: '2.0',
271
+ error: { code: -32001, message: 'Session not found' },
272
+ id: null,
273
+ });
274
+ return;
275
+ }
276
+ // Re-bind so the per-request auth context is current.
277
+ this.ctx!.bindRequestHandlers(
278
+ server,
279
+ { transport: this.kind, stateless: false, sessionId },
280
+ req.raw,
281
+ );
282
+ await transport.handleRequest(req.raw, res.raw, body);
283
+ return;
284
+ }
285
+
286
+ res.status(400).json({
287
+ jsonrpc: '2.0',
288
+ error: {
289
+ code: -32000,
290
+ message: 'Bad Request: Mcp-Session-Id header is required',
291
+ },
292
+ id: null,
293
+ });
294
+ }
295
+
296
+ private async handleGet(req: any, res: any): Promise<void> {
297
+ const adapter = HttpAdapterFactory.getAdapter(req, res);
298
+ const adaptedReq = adapter.adaptRequest(req);
299
+ const adaptedRes = adapter.adaptResponse(res);
300
+
301
+ if (!this.statefulMode) {
302
+ adaptedRes.status(405).json({
303
+ jsonrpc: '2.0',
304
+ error: {
305
+ code: -32000,
306
+ message: 'Method not allowed in stateless mode',
307
+ },
308
+ id: null,
309
+ });
310
+ return;
311
+ }
312
+ const sessionId = adaptedReq.headers['mcp-session-id'] as
313
+ | string
314
+ | undefined;
315
+ const transport = sessionId ? this.transports[sessionId] : undefined;
316
+ if (!transport) {
317
+ adaptedRes.status(404).json({
318
+ jsonrpc: '2.0',
319
+ error: { code: -32001, message: 'Session not found' },
320
+ id: null,
321
+ });
322
+ return;
323
+ }
324
+ await transport.handleRequest(adaptedReq.raw, adaptedRes.raw);
325
+ }
326
+
327
+ private async handleDelete(req: any, res: any): Promise<void> {
328
+ const adapter = HttpAdapterFactory.getAdapter(req, res);
329
+ const adaptedReq = adapter.adaptRequest(req);
330
+ const adaptedRes = adapter.adaptResponse(res);
331
+
332
+ if (!this.statefulMode) {
333
+ adaptedRes.status(405).json({
334
+ jsonrpc: '2.0',
335
+ error: {
336
+ code: -32000,
337
+ message: 'Method not allowed in stateless mode',
338
+ },
339
+ id: null,
340
+ });
341
+ return;
342
+ }
343
+ const sessionId = adaptedReq.headers['mcp-session-id'] as
344
+ | string
345
+ | undefined;
346
+ const transport = sessionId ? this.transports[sessionId] : undefined;
347
+ if (!transport) {
348
+ adaptedRes.status(404).json({
349
+ jsonrpc: '2.0',
350
+ error: { code: -32001, message: 'Session not found' },
351
+ id: null,
352
+ });
353
+ return;
354
+ }
355
+ await transport.handleRequest(adaptedReq.raw, adaptedRes.raw);
356
+ }
357
+
358
+ private async cleanupSession(sessionId: string): Promise<void> {
359
+ const transport = this.transports[sessionId];
360
+ const server = this.servers[sessionId];
361
+ delete this.transports[sessionId];
362
+ delete this.servers[sessionId];
363
+ try {
364
+ await transport?.close();
365
+ await server?.close();
366
+ } catch {
367
+ // best-effort cleanup
368
+ }
369
+ }
370
+ }
371
+
372
+ function isInitializeRequest(body: unknown): boolean {
373
+ const isInit = (msg: unknown): boolean =>
374
+ typeof msg === 'object' &&
375
+ msg !== null &&
376
+ 'method' in msg &&
377
+ (msg as { method?: unknown }).method === 'initialize';
378
+ return Array.isArray(body) ? body.some(isInit) : isInit(body);
379
+ }
380
+
381
+ function ensureLeadingSlash(endpoint: string): string {
382
+ const trimmed = endpoint.trim();
383
+ return trimmed.startsWith('/') ? trimmed : `/${trimmed}`;
384
+ }