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