@modelcontextprotocol/sdk 1.23.0 → 1.24.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 (316) hide show
  1. package/README.md +84 -1507
  2. package/dist/cjs/client/auth-extensions.d.ts +178 -0
  3. package/dist/cjs/client/auth-extensions.d.ts.map +1 -0
  4. package/dist/cjs/client/auth-extensions.js +300 -0
  5. package/dist/cjs/client/auth-extensions.js.map +1 -0
  6. package/dist/cjs/client/auth.d.ts +90 -2
  7. package/dist/cjs/client/auth.d.ts.map +1 -1
  8. package/dist/cjs/client/auth.js +131 -75
  9. package/dist/cjs/client/auth.js.map +1 -1
  10. package/dist/cjs/client/index.d.ts +122 -14
  11. package/dist/cjs/client/index.d.ts.map +1 -1
  12. package/dist/cjs/client/index.js +125 -3
  13. package/dist/cjs/client/index.js.map +1 -1
  14. package/dist/cjs/client/sse.d.ts.map +1 -1
  15. package/dist/cjs/client/sse.js +6 -2
  16. package/dist/cjs/client/sse.js.map +1 -1
  17. package/dist/cjs/client/stdio.d.ts +0 -1
  18. package/dist/cjs/client/stdio.d.ts.map +1 -1
  19. package/dist/cjs/client/stdio.js +36 -11
  20. package/dist/cjs/client/stdio.js.map +1 -1
  21. package/dist/cjs/client/streamableHttp.d.ts +1 -0
  22. package/dist/cjs/client/streamableHttp.d.ts.map +1 -1
  23. package/dist/cjs/client/streamableHttp.js +36 -15
  24. package/dist/cjs/client/streamableHttp.js.map +1 -1
  25. package/dist/cjs/examples/client/simpleClientCredentials.d.ts +20 -0
  26. package/dist/cjs/examples/client/simpleClientCredentials.d.ts.map +1 -0
  27. package/dist/cjs/examples/client/simpleClientCredentials.js +70 -0
  28. package/dist/cjs/examples/client/simpleClientCredentials.js.map +1 -0
  29. package/dist/cjs/examples/client/simpleOAuthClient.js +77 -1
  30. package/dist/cjs/examples/client/simpleOAuthClient.js.map +1 -1
  31. package/dist/cjs/examples/client/simpleStreamableHttp.js +74 -3
  32. package/dist/cjs/examples/client/simpleStreamableHttp.js.map +1 -1
  33. package/dist/cjs/examples/client/simpleTaskInteractiveClient.d.ts +10 -0
  34. package/dist/cjs/examples/client/simpleTaskInteractiveClient.d.ts.map +1 -0
  35. package/dist/cjs/examples/client/simpleTaskInteractiveClient.js +158 -0
  36. package/dist/cjs/examples/client/simpleTaskInteractiveClient.js.map +1 -0
  37. package/dist/cjs/examples/server/elicitationFormExample.js +2 -12
  38. package/dist/cjs/examples/server/elicitationFormExample.js.map +1 -1
  39. package/dist/cjs/examples/server/elicitationUrlExample.js +4 -3
  40. package/dist/cjs/examples/server/elicitationUrlExample.js.map +1 -1
  41. package/dist/cjs/examples/server/jsonResponseStreamableHttp.js +2 -12
  42. package/dist/cjs/examples/server/jsonResponseStreamableHttp.js.map +1 -1
  43. package/dist/cjs/examples/server/simpleSseServer.js +2 -6
  44. package/dist/cjs/examples/server/simpleSseServer.js.map +1 -1
  45. package/dist/cjs/examples/server/simpleStatelessStreamableHttp.js +2 -12
  46. package/dist/cjs/examples/server/simpleStatelessStreamableHttp.js.map +1 -1
  47. package/dist/cjs/examples/server/simpleStreamableHttp.js +61 -21
  48. package/dist/cjs/examples/server/simpleStreamableHttp.js.map +1 -1
  49. package/dist/cjs/examples/server/simpleTaskInteractive.d.ts +12 -0
  50. package/dist/cjs/examples/server/simpleTaskInteractive.d.ts.map +1 -0
  51. package/dist/cjs/examples/server/simpleTaskInteractive.js +603 -0
  52. package/dist/cjs/examples/server/simpleTaskInteractive.js.map +1 -0
  53. package/dist/cjs/examples/server/sseAndStreamableHttpCompatibleServer.js +2 -12
  54. package/dist/cjs/examples/server/sseAndStreamableHttpCompatibleServer.js.map +1 -1
  55. package/dist/cjs/examples/server/ssePollingExample.js +11 -25
  56. package/dist/cjs/examples/server/ssePollingExample.js.map +1 -1
  57. package/dist/cjs/examples/server/standaloneSseWithGetStreamableHttp.js +2 -6
  58. package/dist/cjs/examples/server/standaloneSseWithGetStreamableHttp.js.map +1 -1
  59. package/dist/cjs/examples/server/toolWithSampleServer.js +7 -5
  60. package/dist/cjs/examples/server/toolWithSampleServer.js.map +1 -1
  61. package/dist/cjs/experimental/index.d.ts +13 -0
  62. package/dist/cjs/experimental/index.d.ts.map +1 -0
  63. package/dist/cjs/experimental/index.js +29 -0
  64. package/dist/cjs/experimental/index.js.map +1 -0
  65. package/dist/cjs/experimental/tasks/client.d.ts +121 -0
  66. package/dist/cjs/experimental/tasks/client.d.ts.map +1 -0
  67. package/dist/cjs/experimental/tasks/client.js +189 -0
  68. package/dist/cjs/experimental/tasks/client.js.map +1 -0
  69. package/dist/cjs/experimental/tasks/helpers.d.ts +47 -0
  70. package/dist/cjs/experimental/tasks/helpers.d.ts.map +1 -0
  71. package/dist/cjs/experimental/tasks/helpers.js +70 -0
  72. package/dist/cjs/experimental/tasks/helpers.js.map +1 -0
  73. package/dist/cjs/experimental/tasks/index.d.ts +16 -0
  74. package/dist/cjs/experimental/tasks/index.d.ts.map +1 -0
  75. package/dist/cjs/experimental/tasks/index.js +39 -0
  76. package/dist/cjs/experimental/tasks/index.js.map +1 -0
  77. package/dist/cjs/experimental/tasks/interfaces.d.ts +232 -0
  78. package/dist/cjs/experimental/tasks/interfaces.d.ts.map +1 -0
  79. package/dist/cjs/experimental/tasks/interfaces.js +19 -0
  80. package/dist/cjs/experimental/tasks/interfaces.js.map +1 -0
  81. package/dist/cjs/experimental/tasks/mcp-server.d.ts +77 -0
  82. package/dist/cjs/experimental/tasks/mcp-server.d.ts.map +1 -0
  83. package/dist/cjs/experimental/tasks/mcp-server.js +36 -0
  84. package/dist/cjs/experimental/tasks/mcp-server.js.map +1 -0
  85. package/dist/cjs/experimental/tasks/server.d.ts +83 -0
  86. package/dist/cjs/experimental/tasks/server.d.ts.map +1 -0
  87. package/dist/cjs/experimental/tasks/server.js +93 -0
  88. package/dist/cjs/experimental/tasks/server.js.map +1 -0
  89. package/dist/cjs/experimental/tasks/stores/in-memory.d.ts +94 -0
  90. package/dist/cjs/experimental/tasks/stores/in-memory.d.ts.map +1 -0
  91. package/dist/cjs/experimental/tasks/stores/in-memory.js +253 -0
  92. package/dist/cjs/experimental/tasks/stores/in-memory.js.map +1 -0
  93. package/dist/cjs/experimental/tasks/types.d.ts +10 -0
  94. package/dist/cjs/experimental/tasks/types.d.ts.map +1 -0
  95. package/dist/cjs/experimental/tasks/types.js +28 -0
  96. package/dist/cjs/experimental/tasks/types.js.map +1 -0
  97. package/dist/cjs/server/auth/errors.d.ts +7 -0
  98. package/dist/cjs/server/auth/errors.d.ts.map +1 -1
  99. package/dist/cjs/server/auth/errors.js +11 -2
  100. package/dist/cjs/server/auth/errors.js.map +1 -1
  101. package/dist/cjs/server/auth/handlers/token.d.ts.map +1 -1
  102. package/dist/cjs/server/auth/handlers/token.js +2 -2
  103. package/dist/cjs/server/auth/handlers/token.js.map +1 -1
  104. package/dist/cjs/server/auth/middleware/clientAuth.d.ts.map +1 -1
  105. package/dist/cjs/server/auth/middleware/clientAuth.js +0 -4
  106. package/dist/cjs/server/auth/middleware/clientAuth.js.map +1 -1
  107. package/dist/cjs/server/auth/providers/proxyProvider.d.ts.map +1 -1
  108. package/dist/cjs/server/auth/providers/proxyProvider.js +8 -4
  109. package/dist/cjs/server/auth/providers/proxyProvider.js.map +1 -1
  110. package/dist/cjs/server/auth/router.d.ts.map +1 -1
  111. package/dist/cjs/server/auth/router.js +7 -1
  112. package/dist/cjs/server/auth/router.js.map +1 -1
  113. package/dist/cjs/server/index.d.ts +91 -168
  114. package/dist/cjs/server/index.d.ts.map +1 -1
  115. package/dist/cjs/server/index.js +162 -0
  116. package/dist/cjs/server/index.js.map +1 -1
  117. package/dist/cjs/server/mcp.d.ts +41 -6
  118. package/dist/cjs/server/mcp.d.ts.map +1 -1
  119. package/dist/cjs/server/mcp.js +203 -48
  120. package/dist/cjs/server/mcp.js.map +1 -1
  121. package/dist/cjs/server/middleware/hostHeaderValidation.d.ts +32 -0
  122. package/dist/cjs/server/middleware/hostHeaderValidation.d.ts.map +1 -0
  123. package/dist/cjs/server/middleware/hostHeaderValidation.js +80 -0
  124. package/dist/cjs/server/middleware/hostHeaderValidation.js.map +1 -0
  125. package/dist/cjs/server/sse.d.ts +6 -0
  126. package/dist/cjs/server/sse.d.ts.map +1 -1
  127. package/dist/cjs/server/sse.js +3 -3
  128. package/dist/cjs/server/sse.js.map +1 -1
  129. package/dist/cjs/server/stdio.d.ts +1 -1
  130. package/dist/cjs/server/stdio.js +1 -1
  131. package/dist/cjs/server/streamableHttp.d.ts +11 -0
  132. package/dist/cjs/server/streamableHttp.d.ts.map +1 -1
  133. package/dist/cjs/server/streamableHttp.js +30 -7
  134. package/dist/cjs/server/streamableHttp.js.map +1 -1
  135. package/dist/cjs/server/zod-compat.d.ts +1 -1
  136. package/dist/cjs/server/zod-compat.d.ts.map +1 -1
  137. package/dist/cjs/server/zod-compat.js +2 -2
  138. package/dist/cjs/server/zod-compat.js.map +1 -1
  139. package/dist/cjs/shared/auth.d.ts +1 -1
  140. package/dist/cjs/shared/auth.js +1 -1
  141. package/dist/cjs/shared/auth.js.map +1 -1
  142. package/dist/cjs/shared/protocol.d.ts +220 -3
  143. package/dist/cjs/shared/protocol.d.ts.map +1 -1
  144. package/dist/cjs/shared/protocol.js +699 -38
  145. package/dist/cjs/shared/protocol.js.map +1 -1
  146. package/dist/cjs/shared/responseMessage.d.ts +45 -0
  147. package/dist/cjs/shared/responseMessage.d.ts.map +1 -0
  148. package/dist/cjs/shared/responseMessage.js +23 -0
  149. package/dist/cjs/shared/responseMessage.js.map +1 -0
  150. package/dist/cjs/shared/transport.d.ts +1 -1
  151. package/dist/cjs/types.d.ts +2369 -73
  152. package/dist/cjs/types.d.ts.map +1 -1
  153. package/dist/cjs/types.js +310 -18
  154. package/dist/cjs/types.js.map +1 -1
  155. package/dist/esm/client/auth-extensions.d.ts +178 -0
  156. package/dist/esm/client/auth-extensions.d.ts.map +1 -0
  157. package/dist/esm/client/auth-extensions.js +270 -0
  158. package/dist/esm/client/auth-extensions.js.map +1 -0
  159. package/dist/esm/client/auth.d.ts +90 -2
  160. package/dist/esm/client/auth.d.ts.map +1 -1
  161. package/dist/esm/client/auth.js +129 -75
  162. package/dist/esm/client/auth.js.map +1 -1
  163. package/dist/esm/client/index.d.ts +122 -14
  164. package/dist/esm/client/index.d.ts.map +1 -1
  165. package/dist/esm/client/index.js +126 -4
  166. package/dist/esm/client/index.js.map +1 -1
  167. package/dist/esm/client/sse.d.ts.map +1 -1
  168. package/dist/esm/client/sse.js +7 -3
  169. package/dist/esm/client/sse.js.map +1 -1
  170. package/dist/esm/client/stdio.d.ts +0 -1
  171. package/dist/esm/client/stdio.d.ts.map +1 -1
  172. package/dist/esm/client/stdio.js +36 -11
  173. package/dist/esm/client/stdio.js.map +1 -1
  174. package/dist/esm/client/streamableHttp.d.ts +1 -0
  175. package/dist/esm/client/streamableHttp.d.ts.map +1 -1
  176. package/dist/esm/client/streamableHttp.js +36 -15
  177. package/dist/esm/client/streamableHttp.js.map +1 -1
  178. package/dist/esm/examples/client/simpleClientCredentials.d.ts +20 -0
  179. package/dist/esm/examples/client/simpleClientCredentials.d.ts.map +1 -0
  180. package/dist/esm/examples/client/simpleClientCredentials.js +68 -0
  181. package/dist/esm/examples/client/simpleClientCredentials.js.map +1 -0
  182. package/dist/esm/examples/client/simpleOAuthClient.js +77 -1
  183. package/dist/esm/examples/client/simpleOAuthClient.js.map +1 -1
  184. package/dist/esm/examples/client/simpleStreamableHttp.js +75 -4
  185. package/dist/esm/examples/client/simpleStreamableHttp.js.map +1 -1
  186. package/dist/esm/examples/client/simpleTaskInteractiveClient.d.ts +10 -0
  187. package/dist/esm/examples/client/simpleTaskInteractiveClient.d.ts.map +1 -0
  188. package/dist/esm/examples/client/simpleTaskInteractiveClient.js +156 -0
  189. package/dist/esm/examples/client/simpleTaskInteractiveClient.js.map +1 -0
  190. package/dist/esm/examples/server/elicitationFormExample.js +2 -9
  191. package/dist/esm/examples/server/elicitationFormExample.js.map +1 -1
  192. package/dist/esm/examples/server/elicitationUrlExample.js +4 -3
  193. package/dist/esm/examples/server/elicitationUrlExample.js.map +1 -1
  194. package/dist/esm/examples/server/jsonResponseStreamableHttp.js +2 -9
  195. package/dist/esm/examples/server/jsonResponseStreamableHttp.js.map +1 -1
  196. package/dist/esm/examples/server/simpleSseServer.js +2 -3
  197. package/dist/esm/examples/server/simpleSseServer.js.map +1 -1
  198. package/dist/esm/examples/server/simpleStatelessStreamableHttp.js +2 -9
  199. package/dist/esm/examples/server/simpleStatelessStreamableHttp.js.map +1 -1
  200. package/dist/esm/examples/server/simpleStreamableHttp.js +62 -19
  201. package/dist/esm/examples/server/simpleStreamableHttp.js.map +1 -1
  202. package/dist/esm/examples/server/simpleTaskInteractive.d.ts +12 -0
  203. package/dist/esm/examples/server/simpleTaskInteractive.d.ts.map +1 -0
  204. package/dist/esm/examples/server/simpleTaskInteractive.js +601 -0
  205. package/dist/esm/examples/server/simpleTaskInteractive.js.map +1 -0
  206. package/dist/esm/examples/server/sseAndStreamableHttpCompatibleServer.js +2 -9
  207. package/dist/esm/examples/server/sseAndStreamableHttpCompatibleServer.js.map +1 -1
  208. package/dist/esm/examples/server/ssePollingExample.js +11 -25
  209. package/dist/esm/examples/server/ssePollingExample.js.map +1 -1
  210. package/dist/esm/examples/server/standaloneSseWithGetStreamableHttp.js +2 -3
  211. package/dist/esm/examples/server/standaloneSseWithGetStreamableHttp.js.map +1 -1
  212. package/dist/esm/examples/server/toolWithSampleServer.js +7 -5
  213. package/dist/esm/examples/server/toolWithSampleServer.js.map +1 -1
  214. package/dist/esm/experimental/index.d.ts +13 -0
  215. package/dist/esm/experimental/index.d.ts.map +1 -0
  216. package/dist/esm/experimental/index.js +13 -0
  217. package/dist/esm/experimental/index.js.map +1 -0
  218. package/dist/esm/experimental/tasks/client.d.ts +121 -0
  219. package/dist/esm/experimental/tasks/client.d.ts.map +1 -0
  220. package/dist/esm/experimental/tasks/client.js +185 -0
  221. package/dist/esm/experimental/tasks/client.js.map +1 -0
  222. package/dist/esm/experimental/tasks/helpers.d.ts +47 -0
  223. package/dist/esm/experimental/tasks/helpers.d.ts.map +1 -0
  224. package/dist/esm/experimental/tasks/helpers.js +66 -0
  225. package/dist/esm/experimental/tasks/helpers.js.map +1 -0
  226. package/dist/esm/experimental/tasks/index.d.ts +16 -0
  227. package/dist/esm/experimental/tasks/index.d.ts.map +1 -0
  228. package/dist/esm/experimental/tasks/index.js +20 -0
  229. package/dist/esm/experimental/tasks/index.js.map +1 -0
  230. package/dist/esm/experimental/tasks/interfaces.d.ts +232 -0
  231. package/dist/esm/experimental/tasks/interfaces.d.ts.map +1 -0
  232. package/dist/esm/experimental/tasks/interfaces.js +16 -0
  233. package/dist/esm/experimental/tasks/interfaces.js.map +1 -0
  234. package/dist/esm/experimental/tasks/mcp-server.d.ts +77 -0
  235. package/dist/esm/experimental/tasks/mcp-server.d.ts.map +1 -0
  236. package/dist/esm/experimental/tasks/mcp-server.js +32 -0
  237. package/dist/esm/experimental/tasks/mcp-server.js.map +1 -0
  238. package/dist/esm/experimental/tasks/server.d.ts +83 -0
  239. package/dist/esm/experimental/tasks/server.d.ts.map +1 -0
  240. package/dist/esm/experimental/tasks/server.js +89 -0
  241. package/dist/esm/experimental/tasks/server.js.map +1 -0
  242. package/dist/esm/experimental/tasks/stores/in-memory.d.ts +94 -0
  243. package/dist/esm/experimental/tasks/stores/in-memory.d.ts.map +1 -0
  244. package/dist/esm/experimental/tasks/stores/in-memory.js +248 -0
  245. package/dist/esm/experimental/tasks/stores/in-memory.js.map +1 -0
  246. package/dist/esm/experimental/tasks/types.d.ts +10 -0
  247. package/dist/esm/experimental/tasks/types.d.ts.map +1 -0
  248. package/dist/esm/experimental/tasks/types.js +10 -0
  249. package/dist/esm/experimental/tasks/types.js.map +1 -0
  250. package/dist/esm/server/auth/errors.d.ts +7 -0
  251. package/dist/esm/server/auth/errors.d.ts.map +1 -1
  252. package/dist/esm/server/auth/errors.js +9 -1
  253. package/dist/esm/server/auth/errors.js.map +1 -1
  254. package/dist/esm/server/auth/handlers/token.d.ts.map +1 -1
  255. package/dist/esm/server/auth/handlers/token.js +2 -2
  256. package/dist/esm/server/auth/handlers/token.js.map +1 -1
  257. package/dist/esm/server/auth/middleware/clientAuth.d.ts.map +1 -1
  258. package/dist/esm/server/auth/middleware/clientAuth.js +0 -4
  259. package/dist/esm/server/auth/middleware/clientAuth.js.map +1 -1
  260. package/dist/esm/server/auth/providers/proxyProvider.d.ts.map +1 -1
  261. package/dist/esm/server/auth/providers/proxyProvider.js +8 -4
  262. package/dist/esm/server/auth/providers/proxyProvider.js.map +1 -1
  263. package/dist/esm/server/auth/router.d.ts.map +1 -1
  264. package/dist/esm/server/auth/router.js +7 -1
  265. package/dist/esm/server/auth/router.js.map +1 -1
  266. package/dist/esm/server/index.d.ts +91 -168
  267. package/dist/esm/server/index.d.ts.map +1 -1
  268. package/dist/esm/server/index.js +159 -1
  269. package/dist/esm/server/index.js.map +1 -1
  270. package/dist/esm/server/mcp.d.ts +41 -6
  271. package/dist/esm/server/mcp.d.ts.map +1 -1
  272. package/dist/esm/server/mcp.js +203 -48
  273. package/dist/esm/server/mcp.js.map +1 -1
  274. package/dist/esm/server/middleware/hostHeaderValidation.d.ts +32 -0
  275. package/dist/esm/server/middleware/hostHeaderValidation.d.ts.map +1 -0
  276. package/dist/esm/server/middleware/hostHeaderValidation.js +76 -0
  277. package/dist/esm/server/middleware/hostHeaderValidation.js.map +1 -0
  278. package/dist/esm/server/sse.d.ts +6 -0
  279. package/dist/esm/server/sse.d.ts.map +1 -1
  280. package/dist/esm/server/sse.js +2 -2
  281. package/dist/esm/server/sse.js.map +1 -1
  282. package/dist/esm/server/stdio.d.ts +1 -1
  283. package/dist/esm/server/stdio.js +1 -1
  284. package/dist/esm/server/streamableHttp.d.ts +11 -0
  285. package/dist/esm/server/streamableHttp.d.ts.map +1 -1
  286. package/dist/esm/server/streamableHttp.js +30 -7
  287. package/dist/esm/server/streamableHttp.js.map +1 -1
  288. package/dist/esm/server/zod-compat.d.ts +1 -1
  289. package/dist/esm/server/zod-compat.d.ts.map +1 -1
  290. package/dist/esm/server/zod-compat.js +2 -2
  291. package/dist/esm/server/zod-compat.js.map +1 -1
  292. package/dist/esm/shared/auth.d.ts +1 -1
  293. package/dist/esm/shared/auth.js +1 -1
  294. package/dist/esm/shared/auth.js.map +1 -1
  295. package/dist/esm/shared/protocol.d.ts +220 -3
  296. package/dist/esm/shared/protocol.d.ts.map +1 -1
  297. package/dist/esm/shared/protocol.js +700 -39
  298. package/dist/esm/shared/protocol.js.map +1 -1
  299. package/dist/esm/shared/responseMessage.d.ts +45 -0
  300. package/dist/esm/shared/responseMessage.d.ts.map +1 -0
  301. package/dist/esm/shared/responseMessage.js +19 -0
  302. package/dist/esm/shared/responseMessage.js.map +1 -0
  303. package/dist/esm/shared/transport.d.ts +1 -1
  304. package/dist/esm/types.d.ts +2369 -73
  305. package/dist/esm/types.d.ts.map +1 -1
  306. package/dist/esm/types.js +306 -15
  307. package/dist/esm/types.js.map +1 -1
  308. package/package.json +12 -1
  309. package/dist/cjs/shared/zodTestMatrix.d.ts +0 -16
  310. package/dist/cjs/shared/zodTestMatrix.d.ts.map +0 -1
  311. package/dist/cjs/shared/zodTestMatrix.js +0 -43
  312. package/dist/cjs/shared/zodTestMatrix.js.map +0 -1
  313. package/dist/esm/shared/zodTestMatrix.d.ts +0 -16
  314. package/dist/esm/shared/zodTestMatrix.d.ts.map +0 -1
  315. package/dist/esm/shared/zodTestMatrix.js +0 -17
  316. package/dist/esm/shared/zodTestMatrix.js.map +0 -1
@@ -4,6 +4,7 @@ exports.Protocol = exports.DEFAULT_REQUEST_TIMEOUT_MSEC = void 0;
4
4
  exports.mergeCapabilities = mergeCapabilities;
5
5
  const zod_compat_js_1 = require("../server/zod-compat.js");
6
6
  const types_js_1 = require("../types.js");
7
+ const interfaces_js_1 = require("../experimental/tasks/interfaces.js");
7
8
  const zod_json_schema_compat_js_1 = require("../server/zod-json-schema-compat.js");
8
9
  /**
9
10
  * The default request timeout, in miliseconds.
@@ -24,9 +25,11 @@ class Protocol {
24
25
  this._progressHandlers = new Map();
25
26
  this._timeoutInfo = new Map();
26
27
  this._pendingDebouncedNotifications = new Set();
28
+ // Maps task IDs to progress tokens to keep handlers alive after CreateTaskResult
29
+ this._taskProgressTokens = new Map();
30
+ this._requestResolvers = new Map();
27
31
  this.setNotificationHandler(types_js_1.CancelledNotificationSchema, notification => {
28
- const controller = this._requestHandlerAbortControllers.get(notification.params.requestId);
29
- controller === null || controller === void 0 ? void 0 : controller.abort(notification.params.reason);
32
+ this._oncancel(notification);
30
33
  });
31
34
  this.setNotificationHandler(types_js_1.ProgressNotificationSchema, notification => {
32
35
  this._onprogress(notification);
@@ -34,6 +37,145 @@ class Protocol {
34
37
  this.setRequestHandler(types_js_1.PingRequestSchema,
35
38
  // Automatic pong by default.
36
39
  _request => ({}));
40
+ // Install task handlers if TaskStore is provided
41
+ this._taskStore = _options === null || _options === void 0 ? void 0 : _options.taskStore;
42
+ this._taskMessageQueue = _options === null || _options === void 0 ? void 0 : _options.taskMessageQueue;
43
+ if (this._taskStore) {
44
+ this.setRequestHandler(types_js_1.GetTaskRequestSchema, async (request, extra) => {
45
+ const task = await this._taskStore.getTask(request.params.taskId, extra.sessionId);
46
+ if (!task) {
47
+ throw new types_js_1.McpError(types_js_1.ErrorCode.InvalidParams, 'Failed to retrieve task: Task not found');
48
+ }
49
+ // Per spec: tasks/get responses SHALL NOT include related-task metadata
50
+ // as the taskId parameter is the source of truth
51
+ // @ts-expect-error SendResultT cannot contain GetTaskResult, but we include it in our derived types everywhere else
52
+ return {
53
+ ...task
54
+ };
55
+ });
56
+ this.setRequestHandler(types_js_1.GetTaskPayloadRequestSchema, async (request, extra) => {
57
+ const handleTaskResult = async () => {
58
+ var _a;
59
+ const taskId = request.params.taskId;
60
+ // Deliver queued messages
61
+ if (this._taskMessageQueue) {
62
+ let queuedMessage;
63
+ while ((queuedMessage = await this._taskMessageQueue.dequeue(taskId, extra.sessionId))) {
64
+ // Handle response and error messages by routing them to the appropriate resolver
65
+ if (queuedMessage.type === 'response' || queuedMessage.type === 'error') {
66
+ const message = queuedMessage.message;
67
+ const requestId = message.id;
68
+ // Lookup resolver in _requestResolvers map
69
+ const resolver = this._requestResolvers.get(requestId);
70
+ if (resolver) {
71
+ // Remove resolver from map after invocation
72
+ this._requestResolvers.delete(requestId);
73
+ // Invoke resolver with response or error
74
+ if (queuedMessage.type === 'response') {
75
+ resolver(message);
76
+ }
77
+ else {
78
+ // Convert JSONRPCError to McpError
79
+ const errorMessage = message;
80
+ const error = new types_js_1.McpError(errorMessage.error.code, errorMessage.error.message, errorMessage.error.data);
81
+ resolver(error);
82
+ }
83
+ }
84
+ else {
85
+ // Handle missing resolver gracefully with error logging
86
+ const messageType = queuedMessage.type === 'response' ? 'Response' : 'Error';
87
+ this._onerror(new Error(`${messageType} handler missing for request ${requestId}`));
88
+ }
89
+ // Continue to next message
90
+ continue;
91
+ }
92
+ // Send the message on the response stream by passing the relatedRequestId
93
+ // This tells the transport to write the message to the tasks/result response stream
94
+ await ((_a = this._transport) === null || _a === void 0 ? void 0 : _a.send(queuedMessage.message, { relatedRequestId: extra.requestId }));
95
+ }
96
+ }
97
+ // Now check task status
98
+ const task = await this._taskStore.getTask(taskId, extra.sessionId);
99
+ if (!task) {
100
+ throw new types_js_1.McpError(types_js_1.ErrorCode.InvalidParams, `Task not found: ${taskId}`);
101
+ }
102
+ // Block if task is not terminal (we've already delivered all queued messages above)
103
+ if (!(0, interfaces_js_1.isTerminal)(task.status)) {
104
+ // Wait for status change or new messages
105
+ await this._waitForTaskUpdate(taskId, extra.signal);
106
+ // After waking up, recursively call to deliver any new messages or result
107
+ return await handleTaskResult();
108
+ }
109
+ // If task is terminal, return the result
110
+ if ((0, interfaces_js_1.isTerminal)(task.status)) {
111
+ const result = await this._taskStore.getTaskResult(taskId, extra.sessionId);
112
+ this._clearTaskQueue(taskId);
113
+ return {
114
+ ...result,
115
+ _meta: {
116
+ ...result._meta,
117
+ [types_js_1.RELATED_TASK_META_KEY]: {
118
+ taskId: taskId
119
+ }
120
+ }
121
+ };
122
+ }
123
+ return await handleTaskResult();
124
+ };
125
+ return await handleTaskResult();
126
+ });
127
+ this.setRequestHandler(types_js_1.ListTasksRequestSchema, async (request, extra) => {
128
+ var _a;
129
+ try {
130
+ const { tasks, nextCursor } = await this._taskStore.listTasks((_a = request.params) === null || _a === void 0 ? void 0 : _a.cursor, extra.sessionId);
131
+ // @ts-expect-error SendResultT cannot contain ListTasksResult, but we include it in our derived types everywhere else
132
+ return {
133
+ tasks,
134
+ nextCursor,
135
+ _meta: {}
136
+ };
137
+ }
138
+ catch (error) {
139
+ throw new types_js_1.McpError(types_js_1.ErrorCode.InvalidParams, `Failed to list tasks: ${error instanceof Error ? error.message : String(error)}`);
140
+ }
141
+ });
142
+ this.setRequestHandler(types_js_1.CancelTaskRequestSchema, async (request, extra) => {
143
+ try {
144
+ // Get the current task to check if it's in a terminal state, in case the implementation is not atomic
145
+ const task = await this._taskStore.getTask(request.params.taskId, extra.sessionId);
146
+ if (!task) {
147
+ throw new types_js_1.McpError(types_js_1.ErrorCode.InvalidParams, `Task not found: ${request.params.taskId}`);
148
+ }
149
+ // Reject cancellation of terminal tasks
150
+ if ((0, interfaces_js_1.isTerminal)(task.status)) {
151
+ throw new types_js_1.McpError(types_js_1.ErrorCode.InvalidParams, `Cannot cancel task in terminal status: ${task.status}`);
152
+ }
153
+ await this._taskStore.updateTaskStatus(request.params.taskId, 'cancelled', 'Client cancelled task execution.', extra.sessionId);
154
+ this._clearTaskQueue(request.params.taskId);
155
+ const cancelledTask = await this._taskStore.getTask(request.params.taskId, extra.sessionId);
156
+ if (!cancelledTask) {
157
+ // Task was deleted during cancellation (e.g., cleanup happened)
158
+ throw new types_js_1.McpError(types_js_1.ErrorCode.InvalidParams, `Task not found after cancellation: ${request.params.taskId}`);
159
+ }
160
+ return {
161
+ _meta: {},
162
+ ...cancelledTask
163
+ };
164
+ }
165
+ catch (error) {
166
+ // Re-throw McpError as-is
167
+ if (error instanceof types_js_1.McpError) {
168
+ throw error;
169
+ }
170
+ throw new types_js_1.McpError(types_js_1.ErrorCode.InvalidRequest, `Failed to cancel task: ${error instanceof Error ? error.message : String(error)}`);
171
+ }
172
+ });
173
+ }
174
+ }
175
+ async _oncancel(notification) {
176
+ // Handle request cancellation
177
+ const controller = this._requestHandlerAbortControllers.get(notification.params.requestId);
178
+ controller === null || controller === void 0 ? void 0 : controller.abort(notification.params.reason);
37
179
  }
38
180
  _setupTimeout(messageId, timeout, maxTotalTimeout, onTimeout, resetTimeoutOnProgress = false) {
39
181
  this._timeoutInfo.set(messageId, {
@@ -109,10 +251,11 @@ class Protocol {
109
251
  const responseHandlers = this._responseHandlers;
110
252
  this._responseHandlers = new Map();
111
253
  this._progressHandlers.clear();
254
+ this._taskProgressTokens.clear();
112
255
  this._pendingDebouncedNotifications.clear();
256
+ const error = types_js_1.McpError.fromError(types_js_1.ErrorCode.ConnectionClosed, 'Connection closed');
113
257
  this._transport = undefined;
114
258
  (_a = this.onclose) === null || _a === void 0 ? void 0 : _a.call(this);
115
- const error = types_js_1.McpError.fromError(types_js_1.ErrorCode.ConnectionClosed, 'Connection closed');
116
259
  for (const handler of responseHandlers.values()) {
117
260
  handler(error);
118
261
  }
@@ -134,51 +277,112 @@ class Protocol {
134
277
  .catch(error => this._onerror(new Error(`Uncaught error in notification handler: ${error}`)));
135
278
  }
136
279
  _onrequest(request, extra) {
137
- var _a, _b;
280
+ var _a, _b, _c, _d, _e, _f;
138
281
  const handler = (_a = this._requestHandlers.get(request.method)) !== null && _a !== void 0 ? _a : this.fallbackRequestHandler;
139
282
  // Capture the current transport at request time to ensure responses go to the correct client
140
283
  const capturedTransport = this._transport;
284
+ // Extract taskId from request metadata if present (needed early for method not found case)
285
+ const relatedTaskId = (_d = (_c = (_b = request.params) === null || _b === void 0 ? void 0 : _b._meta) === null || _c === void 0 ? void 0 : _c[types_js_1.RELATED_TASK_META_KEY]) === null || _d === void 0 ? void 0 : _d.taskId;
141
286
  if (handler === undefined) {
142
- capturedTransport === null || capturedTransport === void 0 ? void 0 : capturedTransport.send({
287
+ const errorResponse = {
143
288
  jsonrpc: '2.0',
144
289
  id: request.id,
145
290
  error: {
146
291
  code: types_js_1.ErrorCode.MethodNotFound,
147
292
  message: 'Method not found'
148
293
  }
149
- }).catch(error => this._onerror(new Error(`Failed to send an error response: ${error}`)));
294
+ };
295
+ // Queue or send the error response based on whether this is a task-related request
296
+ if (relatedTaskId && this._taskMessageQueue) {
297
+ this._enqueueTaskMessage(relatedTaskId, {
298
+ type: 'error',
299
+ message: errorResponse,
300
+ timestamp: Date.now()
301
+ }, capturedTransport === null || capturedTransport === void 0 ? void 0 : capturedTransport.sessionId).catch(error => this._onerror(new Error(`Failed to enqueue error response: ${error}`)));
302
+ }
303
+ else {
304
+ capturedTransport === null || capturedTransport === void 0 ? void 0 : capturedTransport.send(errorResponse).catch(error => this._onerror(new Error(`Failed to send an error response: ${error}`)));
305
+ }
150
306
  return;
151
307
  }
152
308
  const abortController = new AbortController();
153
309
  this._requestHandlerAbortControllers.set(request.id, abortController);
310
+ const taskCreationParams = (_e = request.params) === null || _e === void 0 ? void 0 : _e.task;
311
+ const taskStore = this._taskStore ? this.requestTaskStore(request, capturedTransport === null || capturedTransport === void 0 ? void 0 : capturedTransport.sessionId) : undefined;
154
312
  const fullExtra = {
155
313
  signal: abortController.signal,
156
314
  sessionId: capturedTransport === null || capturedTransport === void 0 ? void 0 : capturedTransport.sessionId,
157
- _meta: (_b = request.params) === null || _b === void 0 ? void 0 : _b._meta,
158
- sendNotification: notification => this.notification(notification, { relatedRequestId: request.id }),
159
- sendRequest: (r, resultSchema, options) => this.request(r, resultSchema, { ...options, relatedRequestId: request.id }),
315
+ _meta: (_f = request.params) === null || _f === void 0 ? void 0 : _f._meta,
316
+ sendNotification: async (notification) => {
317
+ // Include related-task metadata if this request is part of a task
318
+ const notificationOptions = { relatedRequestId: request.id };
319
+ if (relatedTaskId) {
320
+ notificationOptions.relatedTask = { taskId: relatedTaskId };
321
+ }
322
+ await this.notification(notification, notificationOptions);
323
+ },
324
+ sendRequest: async (r, resultSchema, options) => {
325
+ var _a, _b;
326
+ // Include related-task metadata if this request is part of a task
327
+ const requestOptions = { ...options, relatedRequestId: request.id };
328
+ if (relatedTaskId && !requestOptions.relatedTask) {
329
+ requestOptions.relatedTask = { taskId: relatedTaskId };
330
+ }
331
+ // Set task status to input_required when sending a request within a task context
332
+ // Use the taskId from options (explicit) or fall back to relatedTaskId (inherited)
333
+ const effectiveTaskId = (_b = (_a = requestOptions.relatedTask) === null || _a === void 0 ? void 0 : _a.taskId) !== null && _b !== void 0 ? _b : relatedTaskId;
334
+ if (effectiveTaskId && taskStore) {
335
+ await taskStore.updateTaskStatus(effectiveTaskId, 'input_required');
336
+ }
337
+ return await this.request(r, resultSchema, requestOptions);
338
+ },
160
339
  authInfo: extra === null || extra === void 0 ? void 0 : extra.authInfo,
161
340
  requestId: request.id,
162
- requestInfo: extra === null || extra === void 0 ? void 0 : extra.requestInfo
341
+ requestInfo: extra === null || extra === void 0 ? void 0 : extra.requestInfo,
342
+ taskId: relatedTaskId,
343
+ taskStore: taskStore,
344
+ taskRequestedTtl: taskCreationParams === null || taskCreationParams === void 0 ? void 0 : taskCreationParams.ttl,
345
+ closeSSEStream: extra === null || extra === void 0 ? void 0 : extra.closeSSEStream,
346
+ closeStandaloneSSEStream: extra === null || extra === void 0 ? void 0 : extra.closeStandaloneSSEStream
163
347
  };
164
348
  // Starting with Promise.resolve() puts any synchronous errors into the monad as well.
165
349
  Promise.resolve()
350
+ .then(() => {
351
+ // If this request asked for task creation, check capability first
352
+ if (taskCreationParams) {
353
+ // Check if the request method supports task creation
354
+ this.assertTaskHandlerCapability(request.method);
355
+ }
356
+ })
166
357
  .then(() => handler(request, fullExtra))
167
- .then(result => {
358
+ .then(async (result) => {
168
359
  if (abortController.signal.aborted) {
360
+ // Request was cancelled
169
361
  return;
170
362
  }
171
- return capturedTransport === null || capturedTransport === void 0 ? void 0 : capturedTransport.send({
363
+ const response = {
172
364
  result,
173
365
  jsonrpc: '2.0',
174
366
  id: request.id
175
- });
176
- }, error => {
367
+ };
368
+ // Queue or send the response based on whether this is a task-related request
369
+ if (relatedTaskId && this._taskMessageQueue) {
370
+ await this._enqueueTaskMessage(relatedTaskId, {
371
+ type: 'response',
372
+ message: response,
373
+ timestamp: Date.now()
374
+ }, capturedTransport === null || capturedTransport === void 0 ? void 0 : capturedTransport.sessionId);
375
+ }
376
+ else {
377
+ await (capturedTransport === null || capturedTransport === void 0 ? void 0 : capturedTransport.send(response));
378
+ }
379
+ }, async (error) => {
177
380
  var _a;
178
381
  if (abortController.signal.aborted) {
382
+ // Request was cancelled
179
383
  return;
180
384
  }
181
- return capturedTransport === null || capturedTransport === void 0 ? void 0 : capturedTransport.send({
385
+ const errorResponse = {
182
386
  jsonrpc: '2.0',
183
387
  id: request.id,
184
388
  error: {
@@ -186,7 +390,18 @@ class Protocol {
186
390
  message: (_a = error.message) !== null && _a !== void 0 ? _a : 'Internal error',
187
391
  ...(error['data'] !== undefined && { data: error['data'] })
188
392
  }
189
- });
393
+ };
394
+ // Queue or send the error response based on whether this is a task-related request
395
+ if (relatedTaskId && this._taskMessageQueue) {
396
+ await this._enqueueTaskMessage(relatedTaskId, {
397
+ type: 'error',
398
+ message: errorResponse,
399
+ timestamp: Date.now()
400
+ }, capturedTransport === null || capturedTransport === void 0 ? void 0 : capturedTransport.sessionId);
401
+ }
402
+ else {
403
+ await (capturedTransport === null || capturedTransport === void 0 ? void 0 : capturedTransport.send(errorResponse));
404
+ }
190
405
  })
191
406
  .catch(error => this._onerror(new Error(`Failed to send response: ${error}`)))
192
407
  .finally(() => {
@@ -208,6 +423,10 @@ class Protocol {
208
423
  this._resetTimeout(messageId);
209
424
  }
210
425
  catch (error) {
426
+ // Clean up if maxTotalTimeout was exceeded
427
+ this._responseHandlers.delete(messageId);
428
+ this._progressHandlers.delete(messageId);
429
+ this._cleanupTimeout(messageId);
211
430
  responseHandler(error);
212
431
  return;
213
432
  }
@@ -216,14 +435,41 @@ class Protocol {
216
435
  }
217
436
  _onresponse(response) {
218
437
  const messageId = Number(response.id);
438
+ // Check if this is a response to a queued request
439
+ const resolver = this._requestResolvers.get(messageId);
440
+ if (resolver) {
441
+ this._requestResolvers.delete(messageId);
442
+ if ((0, types_js_1.isJSONRPCResponse)(response)) {
443
+ resolver(response);
444
+ }
445
+ else {
446
+ const error = new types_js_1.McpError(response.error.code, response.error.message, response.error.data);
447
+ resolver(error);
448
+ }
449
+ return;
450
+ }
219
451
  const handler = this._responseHandlers.get(messageId);
220
452
  if (handler === undefined) {
221
453
  this._onerror(new Error(`Received a response for an unknown message ID: ${JSON.stringify(response)}`));
222
454
  return;
223
455
  }
224
456
  this._responseHandlers.delete(messageId);
225
- this._progressHandlers.delete(messageId);
226
457
  this._cleanupTimeout(messageId);
458
+ // Keep progress handler alive for CreateTaskResult responses
459
+ let isTaskResponse = false;
460
+ if ((0, types_js_1.isJSONRPCResponse)(response) && response.result && typeof response.result === 'object') {
461
+ const result = response.result;
462
+ if (result.task && typeof result.task === 'object') {
463
+ const task = result.task;
464
+ if (typeof task.taskId === 'string') {
465
+ isTaskResponse = true;
466
+ this._taskProgressTokens.set(task.taskId, messageId);
467
+ }
468
+ }
469
+ }
470
+ if (!isTaskResponse) {
471
+ this._progressHandlers.delete(messageId);
472
+ }
227
473
  if ((0, types_js_1.isJSONRPCResponse)(response)) {
228
474
  handler(response);
229
475
  }
@@ -243,20 +489,139 @@ class Protocol {
243
489
  await ((_a = this._transport) === null || _a === void 0 ? void 0 : _a.close());
244
490
  }
245
491
  /**
246
- * Sends a request and wait for a response.
492
+ * Sends a request and returns an AsyncGenerator that yields response messages.
493
+ * The generator is guaranteed to end with either a 'result' or 'error' message.
494
+ *
495
+ * @example
496
+ * ```typescript
497
+ * const stream = protocol.requestStream(request, resultSchema, options);
498
+ * for await (const message of stream) {
499
+ * switch (message.type) {
500
+ * case 'taskCreated':
501
+ * console.log('Task created:', message.task.taskId);
502
+ * break;
503
+ * case 'taskStatus':
504
+ * console.log('Task status:', message.task.status);
505
+ * break;
506
+ * case 'result':
507
+ * console.log('Final result:', message.result);
508
+ * break;
509
+ * case 'error':
510
+ * console.error('Error:', message.error);
511
+ * break;
512
+ * }
513
+ * }
514
+ * ```
515
+ *
516
+ * @experimental Use `client.experimental.tasks.requestStream()` to access this method.
517
+ */
518
+ async *requestStream(request, resultSchema, options) {
519
+ var _a, _b, _c, _d;
520
+ const { task } = options !== null && options !== void 0 ? options : {};
521
+ // For non-task requests, just yield the result
522
+ if (!task) {
523
+ try {
524
+ const result = await this.request(request, resultSchema, options);
525
+ yield { type: 'result', result };
526
+ }
527
+ catch (error) {
528
+ yield {
529
+ type: 'error',
530
+ error: error instanceof types_js_1.McpError ? error : new types_js_1.McpError(types_js_1.ErrorCode.InternalError, String(error))
531
+ };
532
+ }
533
+ return;
534
+ }
535
+ // For task-augmented requests, we need to poll for status
536
+ // First, make the request to create the task
537
+ let taskId;
538
+ try {
539
+ // Send the request and get the CreateTaskResult
540
+ const createResult = await this.request(request, types_js_1.CreateTaskResultSchema, options);
541
+ // Extract taskId from the result
542
+ if (createResult.task) {
543
+ taskId = createResult.task.taskId;
544
+ yield { type: 'taskCreated', task: createResult.task };
545
+ }
546
+ else {
547
+ throw new types_js_1.McpError(types_js_1.ErrorCode.InternalError, 'Task creation did not return a task');
548
+ }
549
+ // Poll for task completion
550
+ while (true) {
551
+ // Get current task status
552
+ const task = await this.getTask({ taskId }, options);
553
+ yield { type: 'taskStatus', task };
554
+ // Check if task is terminal
555
+ if ((0, interfaces_js_1.isTerminal)(task.status)) {
556
+ if (task.status === 'completed') {
557
+ // Get the final result
558
+ const result = await this.getTaskResult({ taskId }, resultSchema, options);
559
+ yield { type: 'result', result };
560
+ }
561
+ else if (task.status === 'failed') {
562
+ yield {
563
+ type: 'error',
564
+ error: new types_js_1.McpError(types_js_1.ErrorCode.InternalError, `Task ${taskId} failed`)
565
+ };
566
+ }
567
+ else if (task.status === 'cancelled') {
568
+ yield {
569
+ type: 'error',
570
+ error: new types_js_1.McpError(types_js_1.ErrorCode.InternalError, `Task ${taskId} was cancelled`)
571
+ };
572
+ }
573
+ return;
574
+ }
575
+ // When input_required, call tasks/result to deliver queued messages
576
+ // (elicitation, sampling) via SSE and block until terminal
577
+ if (task.status === 'input_required') {
578
+ const result = await this.getTaskResult({ taskId }, resultSchema, options);
579
+ yield { type: 'result', result };
580
+ return;
581
+ }
582
+ // Wait before polling again
583
+ const pollInterval = (_c = (_a = task.pollInterval) !== null && _a !== void 0 ? _a : (_b = this._options) === null || _b === void 0 ? void 0 : _b.defaultTaskPollInterval) !== null && _c !== void 0 ? _c : 1000;
584
+ await new Promise(resolve => setTimeout(resolve, pollInterval));
585
+ // Check if cancelled
586
+ (_d = options === null || options === void 0 ? void 0 : options.signal) === null || _d === void 0 ? void 0 : _d.throwIfAborted();
587
+ }
588
+ }
589
+ catch (error) {
590
+ yield {
591
+ type: 'error',
592
+ error: error instanceof types_js_1.McpError ? error : new types_js_1.McpError(types_js_1.ErrorCode.InternalError, String(error))
593
+ };
594
+ }
595
+ }
596
+ /**
597
+ * Sends a request and waits for a response.
247
598
  *
248
599
  * Do not use this method to emit notifications! Use notification() instead.
249
600
  */
250
601
  request(request, resultSchema, options) {
251
- const { relatedRequestId, resumptionToken, onresumptiontoken } = options !== null && options !== void 0 ? options : {};
602
+ const { relatedRequestId, resumptionToken, onresumptiontoken, task, relatedTask } = options !== null && options !== void 0 ? options : {};
603
+ // Send the request
252
604
  return new Promise((resolve, reject) => {
253
- var _a, _b, _c, _d, _e, _f;
605
+ var _a, _b, _c, _d, _e, _f, _g;
606
+ const earlyReject = (error) => {
607
+ reject(error);
608
+ };
254
609
  if (!this._transport) {
255
- reject(new Error('Not connected'));
610
+ earlyReject(new Error('Not connected'));
256
611
  return;
257
612
  }
258
613
  if (((_a = this._options) === null || _a === void 0 ? void 0 : _a.enforceStrictCapabilities) === true) {
259
- this.assertCapabilityForMethod(request.method);
614
+ try {
615
+ this.assertCapabilityForMethod(request.method);
616
+ // If task creation is requested, also check task capabilities
617
+ if (task) {
618
+ this.assertTaskCapability(request.method);
619
+ }
620
+ }
621
+ catch (e) {
622
+ earlyReject(e);
623
+ return;
624
+ }
260
625
  }
261
626
  (_b = options === null || options === void 0 ? void 0 : options.signal) === null || _b === void 0 ? void 0 : _b.throwIfAborted();
262
627
  const messageId = this._requestMessageId++;
@@ -275,6 +640,23 @@ class Protocol {
275
640
  }
276
641
  };
277
642
  }
643
+ // Augment with task creation parameters if provided
644
+ if (task) {
645
+ jsonrpcRequest.params = {
646
+ ...jsonrpcRequest.params,
647
+ task: task
648
+ };
649
+ }
650
+ // Augment with related task metadata if relatedTask is provided
651
+ if (relatedTask) {
652
+ jsonrpcRequest.params = {
653
+ ...jsonrpcRequest.params,
654
+ _meta: {
655
+ ...(((_d = jsonrpcRequest.params) === null || _d === void 0 ? void 0 : _d._meta) || {}),
656
+ [types_js_1.RELATED_TASK_META_KEY]: relatedTask
657
+ }
658
+ };
659
+ }
278
660
  const cancel = (reason) => {
279
661
  var _a;
280
662
  this._responseHandlers.delete(messageId);
@@ -288,7 +670,9 @@ class Protocol {
288
670
  reason: String(reason)
289
671
  }
290
672
  }, { relatedRequestId, resumptionToken, onresumptiontoken }).catch(error => this._onerror(new Error(`Failed to send cancellation: ${error}`)));
291
- reject(reason);
673
+ // Wrap the reason in an McpError if it isn't already
674
+ const error = reason instanceof types_js_1.McpError ? reason : new types_js_1.McpError(types_js_1.ErrorCode.RequestTimeout, String(reason));
675
+ reject(error);
292
676
  };
293
677
  this._responseHandlers.set(messageId, response => {
294
678
  var _a;
@@ -312,32 +696,121 @@ class Protocol {
312
696
  reject(error);
313
697
  }
314
698
  });
315
- (_d = options === null || options === void 0 ? void 0 : options.signal) === null || _d === void 0 ? void 0 : _d.addEventListener('abort', () => {
699
+ (_e = options === null || options === void 0 ? void 0 : options.signal) === null || _e === void 0 ? void 0 : _e.addEventListener('abort', () => {
316
700
  var _a;
317
701
  cancel((_a = options === null || options === void 0 ? void 0 : options.signal) === null || _a === void 0 ? void 0 : _a.reason);
318
702
  });
319
- const timeout = (_e = options === null || options === void 0 ? void 0 : options.timeout) !== null && _e !== void 0 ? _e : exports.DEFAULT_REQUEST_TIMEOUT_MSEC;
703
+ const timeout = (_f = options === null || options === void 0 ? void 0 : options.timeout) !== null && _f !== void 0 ? _f : exports.DEFAULT_REQUEST_TIMEOUT_MSEC;
320
704
  const timeoutHandler = () => cancel(types_js_1.McpError.fromError(types_js_1.ErrorCode.RequestTimeout, 'Request timed out', { timeout }));
321
- this._setupTimeout(messageId, timeout, options === null || options === void 0 ? void 0 : options.maxTotalTimeout, timeoutHandler, (_f = options === null || options === void 0 ? void 0 : options.resetTimeoutOnProgress) !== null && _f !== void 0 ? _f : false);
322
- this._transport.send(jsonrpcRequest, { relatedRequestId, resumptionToken, onresumptiontoken }).catch(error => {
323
- this._cleanupTimeout(messageId);
324
- reject(error);
325
- });
705
+ this._setupTimeout(messageId, timeout, options === null || options === void 0 ? void 0 : options.maxTotalTimeout, timeoutHandler, (_g = options === null || options === void 0 ? void 0 : options.resetTimeoutOnProgress) !== null && _g !== void 0 ? _g : false);
706
+ // Queue request if related to a task
707
+ const relatedTaskId = relatedTask === null || relatedTask === void 0 ? void 0 : relatedTask.taskId;
708
+ if (relatedTaskId) {
709
+ // Store the response resolver for this request so responses can be routed back
710
+ const responseResolver = (response) => {
711
+ const handler = this._responseHandlers.get(messageId);
712
+ if (handler) {
713
+ handler(response);
714
+ }
715
+ else {
716
+ // Log error when resolver is missing, but don't fail
717
+ this._onerror(new Error(`Response handler missing for side-channeled request ${messageId}`));
718
+ }
719
+ };
720
+ this._requestResolvers.set(messageId, responseResolver);
721
+ this._enqueueTaskMessage(relatedTaskId, {
722
+ type: 'request',
723
+ message: jsonrpcRequest,
724
+ timestamp: Date.now()
725
+ }).catch(error => {
726
+ this._cleanupTimeout(messageId);
727
+ reject(error);
728
+ });
729
+ // Don't send through transport - queued messages are delivered via tasks/result only
730
+ // This prevents duplicate delivery for bidirectional transports
731
+ }
732
+ else {
733
+ // No related task - send through transport normally
734
+ this._transport.send(jsonrpcRequest, { relatedRequestId, resumptionToken, onresumptiontoken }).catch(error => {
735
+ this._cleanupTimeout(messageId);
736
+ reject(error);
737
+ });
738
+ }
326
739
  });
327
740
  }
741
+ /**
742
+ * Gets the current status of a task.
743
+ *
744
+ * @experimental Use `client.experimental.tasks.getTask()` to access this method.
745
+ */
746
+ async getTask(params, options) {
747
+ // @ts-expect-error SendRequestT cannot directly contain GetTaskRequest, but we ensure all type instantiations contain it anyways
748
+ return this.request({ method: 'tasks/get', params }, types_js_1.GetTaskResultSchema, options);
749
+ }
750
+ /**
751
+ * Retrieves the result of a completed task.
752
+ *
753
+ * @experimental Use `client.experimental.tasks.getTaskResult()` to access this method.
754
+ */
755
+ async getTaskResult(params, resultSchema, options) {
756
+ // @ts-expect-error SendRequestT cannot directly contain GetTaskPayloadRequest, but we ensure all type instantiations contain it anyways
757
+ return this.request({ method: 'tasks/result', params }, resultSchema, options);
758
+ }
759
+ /**
760
+ * Lists tasks, optionally starting from a pagination cursor.
761
+ *
762
+ * @experimental Use `client.experimental.tasks.listTasks()` to access this method.
763
+ */
764
+ async listTasks(params, options) {
765
+ // @ts-expect-error SendRequestT cannot directly contain ListTasksRequest, but we ensure all type instantiations contain it anyways
766
+ return this.request({ method: 'tasks/list', params }, types_js_1.ListTasksResultSchema, options);
767
+ }
768
+ /**
769
+ * Cancels a specific task.
770
+ *
771
+ * @experimental Use `client.experimental.tasks.cancelTask()` to access this method.
772
+ */
773
+ async cancelTask(params, options) {
774
+ // @ts-expect-error SendRequestT cannot directly contain CancelTaskRequest, but we ensure all type instantiations contain it anyways
775
+ return this.request({ method: 'tasks/cancel', params }, types_js_1.CancelTaskResultSchema, options);
776
+ }
328
777
  /**
329
778
  * Emits a notification, which is a one-way message that does not expect a response.
330
779
  */
331
780
  async notification(notification, options) {
332
- var _a, _b;
781
+ var _a, _b, _c, _d, _e;
333
782
  if (!this._transport) {
334
783
  throw new Error('Not connected');
335
784
  }
336
785
  this.assertNotificationCapability(notification.method);
337
- const debouncedMethods = (_b = (_a = this._options) === null || _a === void 0 ? void 0 : _a.debouncedNotificationMethods) !== null && _b !== void 0 ? _b : [];
786
+ // Queue notification if related to a task
787
+ const relatedTaskId = (_a = options === null || options === void 0 ? void 0 : options.relatedTask) === null || _a === void 0 ? void 0 : _a.taskId;
788
+ if (relatedTaskId) {
789
+ // Build the JSONRPC notification with metadata
790
+ const jsonrpcNotification = {
791
+ ...notification,
792
+ jsonrpc: '2.0',
793
+ params: {
794
+ ...notification.params,
795
+ _meta: {
796
+ ...(((_b = notification.params) === null || _b === void 0 ? void 0 : _b._meta) || {}),
797
+ [types_js_1.RELATED_TASK_META_KEY]: options.relatedTask
798
+ }
799
+ }
800
+ };
801
+ await this._enqueueTaskMessage(relatedTaskId, {
802
+ type: 'notification',
803
+ message: jsonrpcNotification,
804
+ timestamp: Date.now()
805
+ });
806
+ // Don't send through transport - queued messages are delivered via tasks/result only
807
+ // This prevents duplicate delivery for bidirectional transports
808
+ return;
809
+ }
810
+ const debouncedMethods = (_d = (_c = this._options) === null || _c === void 0 ? void 0 : _c.debouncedNotificationMethods) !== null && _d !== void 0 ? _d : [];
338
811
  // A notification can only be debounced if it's in the list AND it's "simple"
339
- // (i.e., has no parameters and no related request ID that could be lost).
340
- const canDebounce = debouncedMethods.includes(notification.method) && !notification.params && !(options === null || options === void 0 ? void 0 : options.relatedRequestId);
812
+ // (i.e., has no parameters and no related request ID or related task that could be lost).
813
+ const canDebounce = debouncedMethods.includes(notification.method) && !notification.params && !(options === null || options === void 0 ? void 0 : options.relatedRequestId) && !(options === null || options === void 0 ? void 0 : options.relatedTask);
341
814
  if (canDebounce) {
342
815
  // If a notification of this type is already scheduled, do nothing.
343
816
  if (this._pendingDebouncedNotifications.has(notification.method)) {
@@ -348,28 +821,54 @@ class Protocol {
348
821
  // Schedule the actual send to happen in the next microtask.
349
822
  // This allows all synchronous calls in the current event loop tick to be coalesced.
350
823
  Promise.resolve().then(() => {
351
- var _a;
824
+ var _a, _b;
352
825
  // Un-mark the notification so the next one can be scheduled.
353
826
  this._pendingDebouncedNotifications.delete(notification.method);
354
827
  // SAFETY CHECK: If the connection was closed while this was pending, abort.
355
828
  if (!this._transport) {
356
829
  return;
357
830
  }
358
- const jsonrpcNotification = {
831
+ let jsonrpcNotification = {
359
832
  ...notification,
360
833
  jsonrpc: '2.0'
361
834
  };
835
+ // Augment with related task metadata if relatedTask is provided
836
+ if (options === null || options === void 0 ? void 0 : options.relatedTask) {
837
+ jsonrpcNotification = {
838
+ ...jsonrpcNotification,
839
+ params: {
840
+ ...jsonrpcNotification.params,
841
+ _meta: {
842
+ ...(((_a = jsonrpcNotification.params) === null || _a === void 0 ? void 0 : _a._meta) || {}),
843
+ [types_js_1.RELATED_TASK_META_KEY]: options.relatedTask
844
+ }
845
+ }
846
+ };
847
+ }
362
848
  // Send the notification, but don't await it here to avoid blocking.
363
849
  // Handle potential errors with a .catch().
364
- (_a = this._transport) === null || _a === void 0 ? void 0 : _a.send(jsonrpcNotification, options).catch(error => this._onerror(error));
850
+ (_b = this._transport) === null || _b === void 0 ? void 0 : _b.send(jsonrpcNotification, options).catch(error => this._onerror(error));
365
851
  });
366
852
  // Return immediately.
367
853
  return;
368
854
  }
369
- const jsonrpcNotification = {
855
+ let jsonrpcNotification = {
370
856
  ...notification,
371
857
  jsonrpc: '2.0'
372
858
  };
859
+ // Augment with related task metadata if relatedTask is provided
860
+ if (options === null || options === void 0 ? void 0 : options.relatedTask) {
861
+ jsonrpcNotification = {
862
+ ...jsonrpcNotification,
863
+ params: {
864
+ ...jsonrpcNotification.params,
865
+ _meta: {
866
+ ...(((_e = jsonrpcNotification.params) === null || _e === void 0 ? void 0 : _e._meta) || {}),
867
+ [types_js_1.RELATED_TASK_META_KEY]: options.relatedTask
868
+ }
869
+ }
870
+ };
871
+ }
373
872
  await this._transport.send(jsonrpcNotification, options);
374
873
  }
375
874
  /**
@@ -417,6 +916,168 @@ class Protocol {
417
916
  removeNotificationHandler(method) {
418
917
  this._notificationHandlers.delete(method);
419
918
  }
919
+ /**
920
+ * Cleans up the progress handler associated with a task.
921
+ * This should be called when a task reaches a terminal status.
922
+ */
923
+ _cleanupTaskProgressHandler(taskId) {
924
+ const progressToken = this._taskProgressTokens.get(taskId);
925
+ if (progressToken !== undefined) {
926
+ this._progressHandlers.delete(progressToken);
927
+ this._taskProgressTokens.delete(taskId);
928
+ }
929
+ }
930
+ /**
931
+ * Enqueues a task-related message for side-channel delivery via tasks/result.
932
+ * @param taskId The task ID to associate the message with
933
+ * @param message The message to enqueue
934
+ * @param sessionId Optional session ID for binding the operation to a specific session
935
+ * @throws Error if taskStore is not configured or if enqueue fails (e.g., queue overflow)
936
+ *
937
+ * Note: If enqueue fails, it's the TaskMessageQueue implementation's responsibility to handle
938
+ * the error appropriately (e.g., by failing the task, logging, etc.). The Protocol layer
939
+ * simply propagates the error.
940
+ */
941
+ async _enqueueTaskMessage(taskId, message, sessionId) {
942
+ var _a;
943
+ // Task message queues are only used when taskStore is configured
944
+ if (!this._taskStore || !this._taskMessageQueue) {
945
+ throw new Error('Cannot enqueue task message: taskStore and taskMessageQueue are not configured');
946
+ }
947
+ const maxQueueSize = (_a = this._options) === null || _a === void 0 ? void 0 : _a.maxTaskQueueSize;
948
+ await this._taskMessageQueue.enqueue(taskId, message, sessionId, maxQueueSize);
949
+ }
950
+ /**
951
+ * Clears the message queue for a task and rejects any pending request resolvers.
952
+ * @param taskId The task ID whose queue should be cleared
953
+ * @param sessionId Optional session ID for binding the operation to a specific session
954
+ */
955
+ async _clearTaskQueue(taskId, sessionId) {
956
+ if (this._taskMessageQueue) {
957
+ // Reject any pending request resolvers
958
+ const messages = await this._taskMessageQueue.dequeueAll(taskId, sessionId);
959
+ for (const message of messages) {
960
+ if (message.type === 'request' && (0, types_js_1.isJSONRPCRequest)(message.message)) {
961
+ // Extract request ID from the message
962
+ const requestId = message.message.id;
963
+ const resolver = this._requestResolvers.get(requestId);
964
+ if (resolver) {
965
+ resolver(new types_js_1.McpError(types_js_1.ErrorCode.InternalError, 'Task cancelled or completed'));
966
+ this._requestResolvers.delete(requestId);
967
+ }
968
+ else {
969
+ // Log error when resolver is missing during cleanup for better observability
970
+ this._onerror(new Error(`Resolver missing for request ${requestId} during task ${taskId} cleanup`));
971
+ }
972
+ }
973
+ }
974
+ }
975
+ }
976
+ /**
977
+ * Waits for a task update (new messages or status change) with abort signal support.
978
+ * Uses polling to check for updates at the task's configured poll interval.
979
+ * @param taskId The task ID to wait for
980
+ * @param signal Abort signal to cancel the wait
981
+ * @returns Promise that resolves when an update occurs or rejects if aborted
982
+ */
983
+ async _waitForTaskUpdate(taskId, signal) {
984
+ var _a, _b, _c;
985
+ // Get the task's poll interval, falling back to default
986
+ let interval = (_b = (_a = this._options) === null || _a === void 0 ? void 0 : _a.defaultTaskPollInterval) !== null && _b !== void 0 ? _b : 1000;
987
+ try {
988
+ const task = await ((_c = this._taskStore) === null || _c === void 0 ? void 0 : _c.getTask(taskId));
989
+ if (task === null || task === void 0 ? void 0 : task.pollInterval) {
990
+ interval = task.pollInterval;
991
+ }
992
+ }
993
+ catch (_d) {
994
+ // Use default interval if task lookup fails
995
+ }
996
+ return new Promise((resolve, reject) => {
997
+ if (signal.aborted) {
998
+ reject(new types_js_1.McpError(types_js_1.ErrorCode.InvalidRequest, 'Request cancelled'));
999
+ return;
1000
+ }
1001
+ // Wait for the poll interval, then resolve so caller can check for updates
1002
+ const timeoutId = setTimeout(resolve, interval);
1003
+ // Clean up timeout and reject if aborted
1004
+ signal.addEventListener('abort', () => {
1005
+ clearTimeout(timeoutId);
1006
+ reject(new types_js_1.McpError(types_js_1.ErrorCode.InvalidRequest, 'Request cancelled'));
1007
+ }, { once: true });
1008
+ });
1009
+ }
1010
+ requestTaskStore(request, sessionId) {
1011
+ const taskStore = this._taskStore;
1012
+ if (!taskStore) {
1013
+ throw new Error('No task store configured');
1014
+ }
1015
+ return {
1016
+ createTask: async (taskParams) => {
1017
+ if (!request) {
1018
+ throw new Error('No request provided');
1019
+ }
1020
+ return await taskStore.createTask(taskParams, request.id, {
1021
+ method: request.method,
1022
+ params: request.params
1023
+ }, sessionId);
1024
+ },
1025
+ getTask: async (taskId) => {
1026
+ const task = await taskStore.getTask(taskId, sessionId);
1027
+ if (!task) {
1028
+ throw new types_js_1.McpError(types_js_1.ErrorCode.InvalidParams, 'Failed to retrieve task: Task not found');
1029
+ }
1030
+ return task;
1031
+ },
1032
+ storeTaskResult: async (taskId, status, result) => {
1033
+ await taskStore.storeTaskResult(taskId, status, result, sessionId);
1034
+ // Get updated task state and send notification
1035
+ const task = await taskStore.getTask(taskId, sessionId);
1036
+ if (task) {
1037
+ const notification = types_js_1.TaskStatusNotificationSchema.parse({
1038
+ method: 'notifications/tasks/status',
1039
+ params: task
1040
+ });
1041
+ await this.notification(notification);
1042
+ if ((0, interfaces_js_1.isTerminal)(task.status)) {
1043
+ this._cleanupTaskProgressHandler(taskId);
1044
+ // Don't clear queue here - it will be cleared after delivery via tasks/result
1045
+ }
1046
+ }
1047
+ },
1048
+ getTaskResult: taskId => {
1049
+ return taskStore.getTaskResult(taskId, sessionId);
1050
+ },
1051
+ updateTaskStatus: async (taskId, status, statusMessage) => {
1052
+ // Check if task exists
1053
+ const task = await taskStore.getTask(taskId, sessionId);
1054
+ if (!task) {
1055
+ throw new types_js_1.McpError(types_js_1.ErrorCode.InvalidParams, `Task "${taskId}" not found - it may have been cleaned up`);
1056
+ }
1057
+ // Don't allow transitions from terminal states
1058
+ if ((0, interfaces_js_1.isTerminal)(task.status)) {
1059
+ throw new types_js_1.McpError(types_js_1.ErrorCode.InvalidParams, `Cannot update task "${taskId}" from terminal status "${task.status}" to "${status}". Terminal states (completed, failed, cancelled) cannot transition to other states.`);
1060
+ }
1061
+ await taskStore.updateTaskStatus(taskId, status, statusMessage, sessionId);
1062
+ // Get updated task state and send notification
1063
+ const updatedTask = await taskStore.getTask(taskId, sessionId);
1064
+ if (updatedTask) {
1065
+ const notification = types_js_1.TaskStatusNotificationSchema.parse({
1066
+ method: 'notifications/tasks/status',
1067
+ params: updatedTask
1068
+ });
1069
+ await this.notification(notification);
1070
+ if ((0, interfaces_js_1.isTerminal)(updatedTask.status)) {
1071
+ this._cleanupTaskProgressHandler(taskId);
1072
+ // Don't clear queue here - it will be cleared after delivery via tasks/result
1073
+ }
1074
+ }
1075
+ },
1076
+ listTasks: cursor => {
1077
+ return taskStore.listTasks(cursor, sessionId);
1078
+ }
1079
+ };
1080
+ }
420
1081
  }
421
1082
  exports.Protocol = Protocol;
422
1083
  function isPlainObject(value) {