@rekog/mcp-nest 1.9.10 → 2.0.0-alpha.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 (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 +1 -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 +6 -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,752 @@
1
+ import { HttpServer, Logger } from '@nestjs/common';
2
+ import {
3
+ BaseRpcContext,
4
+ CustomTransportStrategy,
5
+ MessageHandler,
6
+ Server,
7
+ } from '@nestjs/microservices';
8
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
9
+ import {
10
+ CallToolRequestSchema,
11
+ ErrorCode,
12
+ GetPromptRequestSchema,
13
+ GetPromptResult,
14
+ ListPromptsRequestSchema,
15
+ ListResourcesRequestSchema,
16
+ ListResourceTemplatesRequestSchema,
17
+ ListToolsRequestSchema,
18
+ McpError,
19
+ PromptArgument,
20
+ ReadResourceRequestSchema,
21
+ ReadResourceResult,
22
+ ServerCapabilities,
23
+ } from '@modelcontextprotocol/sdk/types.js';
24
+ import { toJsonSchemaCompat } from '@modelcontextprotocol/sdk/server/zod-json-schema-compat.js';
25
+ import { normalizeObjectSchema } from '@modelcontextprotocol/sdk/server/zod-compat.js';
26
+ import { firstValueFrom } from 'rxjs';
27
+ import { z, ZodType } from 'zod';
28
+
29
+ import {
30
+ MCP_PROMPT_METADATA_KEY,
31
+ MCP_PUBLIC_METADATA_KEY,
32
+ MCP_RESOURCE_METADATA_KEY,
33
+ MCP_RESOURCE_TEMPLATE_METADATA_KEY,
34
+ MCP_ROLES_METADATA_KEY,
35
+ MCP_SCOPES_METADATA_KEY,
36
+ MCP_TOOL_METADATA_KEY,
37
+ PromptMetadata,
38
+ ResourceMetadata,
39
+ ResourceTemplateMetadata,
40
+ ToolMetadata,
41
+ } from '../decorators';
42
+ import { ToolAuthorizationService } from '../services/tool-authorization.service';
43
+ import { createMcpLogger } from '../utils/mcp-logger.factory';
44
+ import type { McpRequest } from '../interfaces/mcp-tool.interface';
45
+ import type {
46
+ DynamicPromptDefinition,
47
+ DynamicPromptHandler,
48
+ DynamicResourceDefinition,
49
+ DynamicResourceHandler,
50
+ DynamicToolDefinition,
51
+ DynamicToolHandler,
52
+ } from '../interfaces';
53
+ import {
54
+ mcpTransportFor,
55
+ McpHandlerExtras,
56
+ McpMethodRef,
57
+ } from './mcp-transport.constants';
58
+ import { McpContext, McpSessionInfo } from './mcp-context';
59
+ import { McpServerOptions } from './mcp-server-options.interface';
60
+ import { McpTransportContext } from './mcp-transport.interface';
61
+ import {
62
+ matchResourceByUri,
63
+ matchResourceTemplateByUri,
64
+ } from './resource-matcher';
65
+
66
+ /** DI token a user can wire (`{ provide: MCP_STRATEGY, useValue: strategy }`) to inject the strategy. */
67
+ export const MCP_STRATEGY = 'MCP_STRATEGY';
68
+
69
+ type Invoke = (payload: unknown, ctx: McpContext) => Promise<unknown>;
70
+
71
+ interface ToolCapability {
72
+ metadata: ToolMetadata;
73
+ invoke: Invoke;
74
+ }
75
+ interface ResourceCapability {
76
+ metadata: ResourceMetadata;
77
+ invoke: Invoke;
78
+ }
79
+ interface TemplateCapability {
80
+ metadata: ResourceTemplateMetadata;
81
+ invoke: Invoke;
82
+ }
83
+ interface PromptCapability {
84
+ metadata: PromptMetadata;
85
+ invoke: Invoke;
86
+ }
87
+
88
+ let strategyIdCounter = 0;
89
+
90
+ /**
91
+ * NestJS microservice transport strategy for the Model Context Protocol.
92
+ *
93
+ * Construct one, declare your `@McpController` classes in a module's
94
+ * `controllers`, and connect it: `app.connectMicroservice({ strategy })`. NestJS
95
+ * binds every `@Tool`/`@Resource`/`@Prompt` handler whose transport id matches
96
+ * this strategy's into its `messageHandlers`. On `listen()` the strategy reads each
97
+ * handler's MCP metadata directly off the decorated method, builds the SDK request
98
+ * handlers, and routes invocations through the standard NestJS RPC pipeline — so
99
+ * MCP tools get guards, pipes, interceptors, and exception filters for free.
100
+ *
101
+ * No `McpModule` or DI discovery service is required.
102
+ */
103
+ export class McpStrategy extends Server implements CustomTransportStrategy {
104
+ public override transportId: symbol;
105
+
106
+ public readonly moduleId: string;
107
+ protected override readonly logger: Logger;
108
+
109
+ private readonly authService = new ToolAuthorizationService();
110
+ private httpAdapter?: HttpServer;
111
+ private built = false;
112
+
113
+ private readonly tools: ToolCapability[] = [];
114
+ private readonly resources: ResourceCapability[] = [];
115
+ private readonly templates: TemplateCapability[] = [];
116
+ private readonly prompts: PromptCapability[] = [];
117
+
118
+ private readonly dynamicTools = new Map<string, ToolCapability>();
119
+ private readonly dynamicResources = new Map<string, ResourceCapability>();
120
+ private readonly dynamicPrompts = new Map<string, PromptCapability>();
121
+
122
+ private readonly eventListeners = new Map<
123
+ string,
124
+ Array<(...a: any[]) => void>
125
+ >();
126
+
127
+ constructor(public readonly options: McpServerOptions) {
128
+ super();
129
+ // A named server gets its own transport id so NestJS routes only the
130
+ // matching `@McpController({ server })` handlers to this strategy; an
131
+ // unnamed server uses the default shared MCP_TRANSPORT id.
132
+ this.transportId = mcpTransportFor(options.server);
133
+ this.moduleId = `mcp-strategy-${strategyIdCounter++}`;
134
+ this.httpAdapter = options.httpAdapter;
135
+ this.logger = createMcpLogger(McpStrategy.name, this.options);
136
+ }
137
+
138
+ /** Provide the Nest HTTP adapter for HTTP transports (call after NestFactory.create). */
139
+ setHttpAdapter(adapter: HttpServer): void {
140
+ this.httpAdapter = adapter;
141
+ }
142
+
143
+ // ---------------------------------------------------------------------------
144
+ // CustomTransportStrategy lifecycle
145
+ // ---------------------------------------------------------------------------
146
+
147
+ async listen(callback: (err?: unknown, ...args: unknown[]) => void) {
148
+ try {
149
+ this.buildCapabilities();
150
+ this.warnIfNamedServerHasNoDecoratorCapabilities();
151
+ const ctx = this.createTransportContext();
152
+ for (const transport of this.options.transports) {
153
+ await transport.start(ctx);
154
+ }
155
+ callback();
156
+ } catch (err) {
157
+ this.logger.error('Failed to start MCP strategy', err as Error);
158
+ callback(err);
159
+ }
160
+ }
161
+
162
+ async close() {
163
+ for (const transport of this.options.transports) {
164
+ try {
165
+ await transport.close();
166
+ } catch (err) {
167
+ this.logger.error('Error closing MCP transport', err as Error);
168
+ }
169
+ }
170
+ this.eventListeners.clear();
171
+ }
172
+
173
+ on<
174
+ EventKey extends string = string,
175
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
176
+ EventCallback extends Function = Function,
177
+ >(event: EventKey, callback: EventCallback): void {
178
+ const list = this.eventListeners.get(event) ?? [];
179
+ list.push(callback as unknown as (...args: any[]) => void);
180
+ this.eventListeners.set(event, list);
181
+ }
182
+
183
+ unwrap<T>(): T {
184
+ return {
185
+ transports: this.options.transports,
186
+ httpAdapter: this.httpAdapter,
187
+ } as T;
188
+ }
189
+
190
+ /**
191
+ * A named server (`McpStrategy({ server })`) that bound zero decorator
192
+ * capabilities almost certainly has a name mismatch: no
193
+ * `@McpController({ server: <name> })` targets it, so it would serve an empty
194
+ * endpoint silently. Warn so the misconfiguration is visible at startup.
195
+ *
196
+ * Scoped to named servers on purpose: an unnamed (default) server is commonly
197
+ * populated only at runtime via `registerTool()` (see the dynamic-capabilities
198
+ * multi-server example), and we don't want to warn on that supported pattern.
199
+ * For the same reason the message notes dynamic registration as the escape hatch.
200
+ */
201
+ private warnIfNamedServerHasNoDecoratorCapabilities(): void {
202
+ if (!this.options.server) return;
203
+ const decoratorCount =
204
+ this.tools.length +
205
+ this.resources.length +
206
+ this.templates.length +
207
+ this.prompts.length;
208
+ if (decoratorCount > 0) return;
209
+ this.logger.warn(
210
+ `MCP server '${this.options.server}' started with no @McpController ` +
211
+ `capabilities bound to it. Check that a @McpController({ server: ` +
212
+ `'${this.options.server}' }) exists and is listed in a module's ` +
213
+ `controllers. (Safe to ignore if this server is populated at runtime ` +
214
+ `via strategy.registerTool()/registerResource()/registerPrompt().)`,
215
+ );
216
+ }
217
+
218
+ // ---------------------------------------------------------------------------
219
+ // Capability discovery — straight from the bound handlers' metadata
220
+ // ---------------------------------------------------------------------------
221
+
222
+ private buildCapabilities(): void {
223
+ if (this.built) return;
224
+ this.built = true;
225
+
226
+ for (const [route, handler] of this.messageHandlers) {
227
+ const extras = (handler as MessageHandler & { extras?: McpHandlerExtras })
228
+ .extras;
229
+ if (!extras?.mcpType) {
230
+ // Prune stray non-MCP @MessagePattern handlers bound via the
231
+ // undefined-transport clause, so the MCP server only sees MCP handlers.
232
+ this.messageHandlers.delete(route);
233
+ continue;
234
+ }
235
+
236
+ const { mcpType, mcpMethodKey, mcpMethodRef } = extras;
237
+ const invoke: Invoke = (payload, ctx) =>
238
+ this.invokeViaPipeline(handler, payload, ctx);
239
+
240
+ switch (mcpType) {
241
+ case 'tool':
242
+ this.tools.push({
243
+ metadata: this.readToolMetadata(mcpMethodRef, mcpMethodKey),
244
+ invoke,
245
+ });
246
+ break;
247
+ case 'resource':
248
+ this.resources.push({
249
+ metadata: this.readMetadata<ResourceMetadata>(
250
+ MCP_RESOURCE_METADATA_KEY,
251
+ mcpMethodRef,
252
+ mcpMethodKey,
253
+ ),
254
+ invoke,
255
+ });
256
+ break;
257
+ case 'resource-template':
258
+ this.templates.push({
259
+ metadata: this.readMetadata<ResourceTemplateMetadata>(
260
+ MCP_RESOURCE_TEMPLATE_METADATA_KEY,
261
+ mcpMethodRef,
262
+ mcpMethodKey,
263
+ ),
264
+ invoke,
265
+ });
266
+ break;
267
+ case 'prompt':
268
+ this.prompts.push({
269
+ metadata: this.readMetadata<PromptMetadata>(
270
+ MCP_PROMPT_METADATA_KEY,
271
+ mcpMethodRef,
272
+ mcpMethodKey,
273
+ ),
274
+ invoke,
275
+ });
276
+ break;
277
+ }
278
+ }
279
+ }
280
+
281
+ private readToolMetadata(
282
+ methodRef: McpMethodRef,
283
+ methodKey: string,
284
+ ): ToolMetadata {
285
+ const base: ToolMetadata = {
286
+ ...(Reflect.getMetadata(
287
+ MCP_TOOL_METADATA_KEY,
288
+ methodRef,
289
+ ) as ToolMetadata),
290
+ };
291
+ if (!base.name) base.name = methodKey;
292
+ if (!base.parameters) base.parameters = z.object({});
293
+
294
+ const isPublic = Reflect.getMetadata(MCP_PUBLIC_METADATA_KEY, methodRef);
295
+ const requiredScopes = Reflect.getMetadata(
296
+ MCP_SCOPES_METADATA_KEY,
297
+ methodRef,
298
+ );
299
+ const requiredRoles = Reflect.getMetadata(
300
+ MCP_ROLES_METADATA_KEY,
301
+ methodRef,
302
+ );
303
+ if (isPublic !== undefined) base.isPublic = isPublic;
304
+ if (requiredScopes) base.requiredScopes = requiredScopes;
305
+ if (requiredRoles) base.requiredRoles = requiredRoles;
306
+ return base;
307
+ }
308
+
309
+ private readMetadata<T extends { name?: string }>(
310
+ key: string,
311
+ methodRef: McpMethodRef,
312
+ methodKey: string,
313
+ ): T {
314
+ const metadata = { ...(Reflect.getMetadata(key, methodRef) as T) };
315
+ if (!metadata.name) metadata.name = methodKey;
316
+ return metadata;
317
+ }
318
+
319
+ private getTools(): ToolCapability[] {
320
+ return [...this.tools, ...this.dynamicTools.values()];
321
+ }
322
+ private getResources(): ResourceCapability[] {
323
+ return [...this.resources, ...this.dynamicResources.values()];
324
+ }
325
+ private getTemplates(): TemplateCapability[] {
326
+ return [...this.templates];
327
+ }
328
+ private getPrompts(): PromptCapability[] {
329
+ return [...this.prompts, ...this.dynamicPrompts.values()];
330
+ }
331
+
332
+ // ---------------------------------------------------------------------------
333
+ // SDK server + request handlers
334
+ // ---------------------------------------------------------------------------
335
+
336
+ private createTransportContext(): McpTransportContext {
337
+ return {
338
+ createServer: () => this.createServer(),
339
+ bindRequestHandlers: (server, session, rawRequest) =>
340
+ this.bindRequestHandlers(server, session, rawRequest),
341
+ httpAdapter: this.httpAdapter,
342
+ options: this.options,
343
+ logger: this.logger,
344
+ };
345
+ }
346
+
347
+ private createServer(): McpServer {
348
+ const capabilities: ServerCapabilities = {
349
+ ...(this.options.capabilities ?? {}),
350
+ };
351
+ if (this.getTools().length > 0) {
352
+ capabilities.tools = capabilities.tools ?? { listChanged: true };
353
+ }
354
+ if (this.getResources().length + this.getTemplates().length > 0) {
355
+ capabilities.resources = capabilities.resources ?? { listChanged: true };
356
+ }
357
+ if (this.getPrompts().length > 0) {
358
+ capabilities.prompts = capabilities.prompts ?? { listChanged: true };
359
+ }
360
+
361
+ const server = new McpServer(
362
+ {
363
+ name: this.options.name,
364
+ version: this.options.version,
365
+ ...(this.options.title && { title: this.options.title }),
366
+ ...(this.options.description && {
367
+ description: this.options.description,
368
+ }),
369
+ ...(this.options.websiteUrl && { websiteUrl: this.options.websiteUrl }),
370
+ ...(this.options.icons && { icons: this.options.icons }),
371
+ },
372
+ { capabilities, instructions: this.options.instructions ?? '' },
373
+ );
374
+
375
+ return this.options.serverMutator
376
+ ? this.options.serverMutator(server)
377
+ : server;
378
+ }
379
+
380
+ bindRequestHandlers(
381
+ server: McpServer,
382
+ session: Pick<McpSessionInfo, 'transport' | 'stateless' | 'sessionId'>,
383
+ rawRequest?: unknown,
384
+ ): void {
385
+ this.bindToolHandlers(server, session, rawRequest);
386
+ this.bindResourceHandlers(server, session, rawRequest);
387
+ this.bindPromptHandlers(server, session, rawRequest);
388
+ }
389
+
390
+ private buildContext(
391
+ server: McpServer,
392
+ request: McpRequest,
393
+ session: Pick<McpSessionInfo, 'transport' | 'stateless' | 'sessionId'>,
394
+ rawRequest?: unknown,
395
+ ): McpContext {
396
+ const sessionId =
397
+ session.sessionId ??
398
+ (server.server.transport as { sessionId?: string } | undefined)
399
+ ?.sessionId;
400
+ return new McpContext(
401
+ [server, request, { ...session, sessionId }, rawRequest],
402
+ this.logger,
403
+ );
404
+ }
405
+
406
+ private getUser(rawRequest?: unknown): any {
407
+ return rawRequest ? (rawRequest as { user?: unknown }).user : undefined;
408
+ }
409
+
410
+ private bindToolHandlers(
411
+ server: McpServer,
412
+ session: Pick<McpSessionInfo, 'transport' | 'stateless' | 'sessionId'>,
413
+ rawRequest?: unknown,
414
+ ): void {
415
+ if (this.getTools().length === 0) return;
416
+
417
+ const allowUnauthenticatedAccess =
418
+ this.options.allowUnauthenticatedAccess ?? false;
419
+
420
+ server.server.setRequestHandler(ListToolsRequestSchema, () => {
421
+ const user = this.getUser(rawRequest);
422
+ const tools = this.getTools()
423
+ .filter((tool) =>
424
+ this.authService.canAccessTool(
425
+ user,
426
+ tool,
427
+ allowUnauthenticatedAccess,
428
+ ),
429
+ )
430
+ .map((tool) => {
431
+ const schema: Record<string, unknown> = {
432
+ name: tool.metadata.name,
433
+ description: tool.metadata.description,
434
+ annotations: tool.metadata.annotations,
435
+ _meta: tool.metadata._meta,
436
+ };
437
+ const securitySchemes = this.authService.generateSecuritySchemes(
438
+ tool,
439
+ allowUnauthenticatedAccess,
440
+ );
441
+ if (securitySchemes.length > 0) {
442
+ schema._meta = { ...(schema._meta as object), securitySchemes };
443
+ }
444
+ const input = normalizeObjectSchema(tool.metadata.parameters);
445
+ if (input) schema.inputSchema = toJsonSchemaCompat(input);
446
+ const output = normalizeObjectSchema(tool.metadata.outputSchema);
447
+ if (output) {
448
+ schema.outputSchema = {
449
+ ...toJsonSchemaCompat(output),
450
+ type: 'object',
451
+ };
452
+ }
453
+ return schema;
454
+ });
455
+ return { tools };
456
+ });
457
+
458
+ server.server.setRequestHandler(CallToolRequestSchema, async (request) => {
459
+ const tool = this.getTools().find(
460
+ (t) => t.metadata.name === request.params.name,
461
+ );
462
+ if (!tool) {
463
+ throw new McpError(
464
+ ErrorCode.MethodNotFound,
465
+ `Unknown tool: ${request.params.name}`,
466
+ );
467
+ }
468
+
469
+ this.authService.validateToolAccess(
470
+ this.getUser(rawRequest),
471
+ tool,
472
+ allowUnauthenticatedAccess,
473
+ );
474
+
475
+ if (tool.metadata.parameters) {
476
+ const validation = tool.metadata.parameters.safeParse(
477
+ request.params.arguments ?? {},
478
+ );
479
+ if (!validation.success) {
480
+ const issues = validation.error.issues
481
+ .map((issue) => {
482
+ const path = issue.path.length > 0 ? issue.path.join('.') : '';
483
+ return `${path ? `[${path}]: ` : ''}${issue.message}`;
484
+ })
485
+ .join('; ');
486
+ return {
487
+ content: [{ type: 'text', text: `Invalid parameters: ${issues}` }],
488
+ isError: true,
489
+ };
490
+ }
491
+ request.params.arguments = validation.data as Record<string, unknown>;
492
+ }
493
+
494
+ const ctx = this.buildContext(server, request, session, rawRequest);
495
+ try {
496
+ const result = await tool.invoke(request.params.arguments ?? {}, ctx);
497
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return
498
+ return this.formatToolResult(result, tool.metadata.outputSchema);
499
+ } catch (error) {
500
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return
501
+ return this.toErrorResult(error);
502
+ }
503
+ });
504
+ }
505
+
506
+ private bindResourceHandlers(
507
+ server: McpServer,
508
+ session: Pick<McpSessionInfo, 'transport' | 'stateless' | 'sessionId'>,
509
+ rawRequest?: unknown,
510
+ ): void {
511
+ if (this.getResources().length + this.getTemplates().length === 0) return;
512
+
513
+ server.server.setRequestHandler(ListResourcesRequestSchema, () => ({
514
+ resources: this.getResources().map((r) => r.metadata),
515
+ }));
516
+
517
+ server.server.setRequestHandler(ListResourceTemplatesRequestSchema, () => ({
518
+ resourceTemplates: this.getTemplates().map((r) => r.metadata),
519
+ }));
520
+
521
+ server.server.setRequestHandler(
522
+ ReadResourceRequestSchema,
523
+ async (request) => {
524
+ const uri = request.params.uri;
525
+ const templateMatch = matchResourceTemplateByUri(
526
+ this.getTemplates().map((cap) => ({
527
+ uriTemplate: cap.metadata.uriTemplate,
528
+ cap,
529
+ })),
530
+ uri,
531
+ );
532
+ const resourceMatch = matchResourceByUri(
533
+ this.getResources().map((cap) => ({ uri: cap.metadata.uri, cap })),
534
+ uri,
535
+ );
536
+
537
+ let invoke: Invoke;
538
+ let params: Record<string, unknown>;
539
+ if (templateMatch) {
540
+ invoke = templateMatch.template.cap.invoke;
541
+ params = { ...templateMatch.params, ...request.params };
542
+ } else if (resourceMatch) {
543
+ invoke = resourceMatch.resource.cap.invoke;
544
+ params = { ...resourceMatch.params, ...request.params };
545
+ } else {
546
+ throw new McpError(
547
+ ErrorCode.MethodNotFound,
548
+ `Unknown resource: ${uri}`,
549
+ );
550
+ }
551
+
552
+ const ctx = this.buildContext(server, request, session, rawRequest);
553
+ return (await invoke(params, ctx)) as ReadResourceResult;
554
+ },
555
+ );
556
+ }
557
+
558
+ private bindPromptHandlers(
559
+ server: McpServer,
560
+ session: Pick<McpSessionInfo, 'transport' | 'stateless' | 'sessionId'>,
561
+ rawRequest?: unknown,
562
+ ): void {
563
+ if (this.getPrompts().length === 0) return;
564
+
565
+ server.server.setRequestHandler(ListPromptsRequestSchema, () => ({
566
+ prompts: this.getPrompts().map((prompt) => ({
567
+ name: prompt.metadata.name,
568
+ description: prompt.metadata.description,
569
+ arguments: prompt.metadata.parameters
570
+ ? Object.entries(prompt.metadata.parameters.shape).map(
571
+ ([name, field]): PromptArgument => ({
572
+ name,
573
+ description: field.description,
574
+ required: !field.isOptional(),
575
+ }),
576
+ )
577
+ : [],
578
+ })),
579
+ }));
580
+
581
+ server.server.setRequestHandler(GetPromptRequestSchema, async (request) => {
582
+ const prompt = this.getPrompts().find(
583
+ (p) => p.metadata.name === request.params.name,
584
+ );
585
+ if (!prompt) {
586
+ throw new McpError(
587
+ ErrorCode.MethodNotFound,
588
+ `Unknown prompt: ${request.params.name}`,
589
+ );
590
+ }
591
+ const ctx = this.buildContext(server, request, session, rawRequest);
592
+ return (await prompt.invoke(
593
+ request.params.arguments,
594
+ ctx,
595
+ )) as GetPromptResult;
596
+ });
597
+ }
598
+
599
+ // ---------------------------------------------------------------------------
600
+ // RPC pipeline invocation
601
+ // ---------------------------------------------------------------------------
602
+
603
+ private async invokeViaPipeline(
604
+ handler: MessageHandler,
605
+ payload: unknown,
606
+ ctx: BaseRpcContext,
607
+ ): Promise<unknown> {
608
+ let resultPromise!: Promise<unknown>;
609
+ const done = () => {
610
+ resultPromise = (async () => {
611
+ const resultOrStream: unknown = await handler(payload, ctx);
612
+ return firstValueFrom(this.transformToObservable(resultOrStream));
613
+ })();
614
+ return resultPromise;
615
+ };
616
+ // onProcessingStartHook may be async (request-scoped lifecycle); the base
617
+ // type declares it `void`, so wrap to await defensively without a lint error.
618
+ await Promise.resolve(
619
+ this.onProcessingStartHook(this.transportId, ctx, done),
620
+ );
621
+ try {
622
+ return await resultPromise;
623
+ } finally {
624
+ this.onProcessingEndHook?.(this.transportId, ctx);
625
+ }
626
+ }
627
+
628
+ private formatToolResult(result: any, outputSchema?: ZodType): any {
629
+ if (result && typeof result === 'object' && Array.isArray(result.content)) {
630
+ return result;
631
+ }
632
+ const defaultContent = [{ type: 'text', text: JSON.stringify(result) }];
633
+ if (outputSchema) {
634
+ const validation = outputSchema.safeParse(result);
635
+ if (!validation.success) {
636
+ throw new McpError(
637
+ ErrorCode.InternalError,
638
+ `Tool result does not match outputSchema: ${validation.error.message}`,
639
+ );
640
+ }
641
+ return { structuredContent: validation.data, content: defaultContent };
642
+ }
643
+ return { content: defaultContent };
644
+ }
645
+
646
+ /**
647
+ * Turn an error thrown while invoking a tool into a result the calling agent
648
+ * can act on.
649
+ *
650
+ * We deliberately surface the most specific message available so the agent can
651
+ * tell *why* the call failed and whether retrying makes sense:
652
+ *
653
+ * - `McpError` is re-thrown so the SDK emits a real JSON-RPC error with its
654
+ * code (e.g. invalid params, output-schema mismatch).
655
+ * - Errors raised intentionally for the client — `throw new RpcException('…')`
656
+ * or anything surfaced by a `@UseFilters` exception filter — carry an
657
+ * explicit message/payload, which we return verbatim as an `isError` result.
658
+ * - Unexpected errors (`throw new Error('boom')` in a handler) are masked to a
659
+ * generic "Internal server error" by NestJS's default RPC exception handler
660
+ * *before* they reach here. That is intentional (don't leak internals); to
661
+ * surface a custom message, throw `RpcException` or register the exported
662
+ * `McpExceptionFilter`. Either way the agent gets `isError: true` and knows
663
+ * the failure is server-side, not a bad-input problem it can fix by retrying.
664
+ */
665
+ private toErrorResult(error: unknown): any {
666
+ if (error instanceof McpError) {
667
+ throw error;
668
+ }
669
+ let message = 'Internal server error';
670
+ if (error instanceof Error) {
671
+ message = error.message;
672
+ } else if (typeof error === 'string') {
673
+ message = error;
674
+ } else if (
675
+ error &&
676
+ typeof error === 'object' &&
677
+ typeof (error as { message?: unknown }).message === 'string'
678
+ ) {
679
+ // RpcException payloads arrive as `{ status: 'error', message: '…' }`.
680
+ message = (error as { message: string }).message;
681
+ }
682
+ this.logger.error(message);
683
+ return { content: [{ type: 'text', text: message }], isError: true };
684
+ }
685
+
686
+ // ---------------------------------------------------------------------------
687
+ // Dynamic capability registration
688
+ // ---------------------------------------------------------------------------
689
+
690
+ registerTool(definition: DynamicToolDefinition): void {
691
+ const handler: DynamicToolHandler = definition.handler;
692
+ this.dynamicTools.set(definition.name, {
693
+ metadata: {
694
+ name: definition.name,
695
+ description: definition.description,
696
+ parameters: definition.parameters ?? z.object({}),
697
+ outputSchema: definition.outputSchema,
698
+ annotations: definition.annotations,
699
+ _meta: definition._meta,
700
+ isPublic: definition.isPublic,
701
+ requiredScopes: definition.requiredScopes,
702
+ requiredRoles: definition.requiredRoles,
703
+ },
704
+ invoke: (payload, ctx) =>
705
+ Promise.resolve(
706
+ handler(payload as any, ctx, ctx.getRawRequest()) as unknown,
707
+ ),
708
+ });
709
+ }
710
+
711
+ registerResource(definition: DynamicResourceDefinition): void {
712
+ const handler: DynamicResourceHandler = definition.handler;
713
+ this.dynamicResources.set(definition.uri, {
714
+ metadata: {
715
+ uri: definition.uri,
716
+ name: definition.name ?? definition.uri,
717
+ description: definition.description,
718
+ mimeType: definition.mimeType,
719
+ _meta: definition._meta,
720
+ },
721
+ invoke: (payload, ctx) =>
722
+ Promise.resolve(
723
+ handler(payload as any, ctx, ctx.getRawRequest()) as unknown,
724
+ ),
725
+ });
726
+ }
727
+
728
+ registerPrompt(definition: DynamicPromptDefinition): void {
729
+ const handler: DynamicPromptHandler = definition.handler;
730
+ this.dynamicPrompts.set(definition.name, {
731
+ metadata: {
732
+ name: definition.name,
733
+ description: definition.description,
734
+ parameters: definition.parameters,
735
+ },
736
+ invoke: (payload, ctx) =>
737
+ Promise.resolve(
738
+ handler(payload as any, ctx, ctx.getRawRequest()) as unknown,
739
+ ),
740
+ });
741
+ }
742
+
743
+ removeTool(name: string): void {
744
+ this.dynamicTools.delete(name);
745
+ }
746
+ removeResource(uri: string): void {
747
+ this.dynamicResources.delete(uri);
748
+ }
749
+ removePrompt(name: string): void {
750
+ this.dynamicPrompts.delete(name);
751
+ }
752
+ }