@animalabs/agent-framework 0.22.2 → 0.23.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 (997) hide show
  1. package/README.md +108 -4
  2. package/dist/src/agent.d.ts +108 -17
  3. package/dist/src/agent.d.ts.map +1 -1
  4. package/dist/src/agent.js +207 -67
  5. package/dist/src/agent.js.map +1 -1
  6. package/dist/src/api/mcp-server-core.js +1 -1
  7. package/dist/src/api/mcp-server-core.js.map +1 -1
  8. package/dist/src/api/server.d.ts.map +1 -1
  9. package/dist/src/api/server.js +5 -1
  10. package/dist/src/api/server.js.map +1 -1
  11. package/dist/src/api/types.d.ts +1 -1
  12. package/dist/src/api/types.d.ts.map +1 -1
  13. package/dist/src/branch-names.d.ts +14 -0
  14. package/dist/src/branch-names.d.ts.map +1 -0
  15. package/dist/src/branch-names.js +22 -0
  16. package/dist/src/branch-names.js.map +1 -0
  17. package/dist/src/closest-names.d.ts +28 -0
  18. package/dist/src/closest-names.d.ts.map +1 -0
  19. package/dist/src/closest-names.js +98 -0
  20. package/dist/src/closest-names.js.map +1 -0
  21. package/dist/src/code-execution/index.d.ts +1 -1
  22. package/dist/src/code-execution/index.d.ts.map +1 -1
  23. package/dist/src/code-execution/index.js.map +1 -1
  24. package/dist/src/code-execution/py-runner.d.ts +50 -7
  25. package/dist/src/code-execution/py-runner.d.ts.map +1 -1
  26. package/dist/src/code-execution/py-runner.js +258 -90
  27. package/dist/src/code-execution/py-runner.js.map +1 -1
  28. package/dist/src/code-execution/runtime-py.d.ts +3 -2
  29. package/dist/src/code-execution/runtime-py.d.ts.map +1 -1
  30. package/dist/src/code-execution/runtime-py.js +94 -8
  31. package/dist/src/code-execution/runtime-py.js.map +1 -1
  32. package/dist/src/code-execution/tool-definition.d.ts +17 -1
  33. package/dist/src/code-execution/tool-definition.d.ts.map +1 -1
  34. package/dist/src/code-execution/tool-definition.js +72 -6
  35. package/dist/src/code-execution/tool-definition.js.map +1 -1
  36. package/dist/src/config-checks.d.ts +28 -0
  37. package/dist/src/config-checks.d.ts.map +1 -0
  38. package/dist/src/config-checks.js +56 -0
  39. package/dist/src/config-checks.js.map +1 -0
  40. package/dist/src/deadline-timer.d.ts +21 -0
  41. package/dist/src/deadline-timer.d.ts.map +1 -0
  42. package/dist/src/deadline-timer.js +43 -0
  43. package/dist/src/deadline-timer.js.map +1 -0
  44. package/dist/src/error-message.d.ts +30 -0
  45. package/dist/src/error-message.d.ts.map +1 -0
  46. package/dist/src/error-message.js +50 -0
  47. package/dist/src/error-message.js.map +1 -0
  48. package/dist/src/framework.d.ts +1529 -165
  49. package/dist/src/framework.d.ts.map +1 -1
  50. package/dist/src/framework.js +8264 -1939
  51. package/dist/src/framework.js.map +1 -1
  52. package/dist/src/gate/event-gate.d.ts +8 -0
  53. package/dist/src/gate/event-gate.d.ts.map +1 -1
  54. package/dist/src/gate/event-gate.js +36 -5
  55. package/dist/src/gate/event-gate.js.map +1 -1
  56. package/dist/src/held-writes.d.ts +16 -0
  57. package/dist/src/held-writes.d.ts.map +1 -0
  58. package/dist/src/held-writes.js +56 -0
  59. package/dist/src/held-writes.js.map +1 -0
  60. package/dist/src/index.d.ts +10 -4
  61. package/dist/src/index.d.ts.map +1 -1
  62. package/dist/src/index.js +11 -5
  63. package/dist/src/index.js.map +1 -1
  64. package/dist/src/mcpl/capability-grant.d.ts +4 -0
  65. package/dist/src/mcpl/capability-grant.d.ts.map +1 -1
  66. package/dist/src/mcpl/capability-grant.js +1 -1
  67. package/dist/src/mcpl/capability-grant.js.map +1 -1
  68. package/dist/src/mcpl/channel-registry.d.ts +233 -18
  69. package/dist/src/mcpl/channel-registry.d.ts.map +1 -1
  70. package/dist/src/mcpl/channel-registry.js +975 -386
  71. package/dist/src/mcpl/channel-registry.js.map +1 -1
  72. package/dist/src/mcpl/checkpoint-manager.d.ts +21 -1
  73. package/dist/src/mcpl/checkpoint-manager.d.ts.map +1 -1
  74. package/dist/src/mcpl/checkpoint-manager.js +91 -30
  75. package/dist/src/mcpl/checkpoint-manager.js.map +1 -1
  76. package/dist/src/mcpl/conversation-router.d.ts +19 -3
  77. package/dist/src/mcpl/conversation-router.d.ts.map +1 -1
  78. package/dist/src/mcpl/conversation-router.js +23 -8
  79. package/dist/src/mcpl/conversation-router.js.map +1 -1
  80. package/dist/src/mcpl/convert-block.d.ts +20 -0
  81. package/dist/src/mcpl/convert-block.d.ts.map +1 -0
  82. package/dist/src/mcpl/convert-block.js +88 -0
  83. package/dist/src/mcpl/convert-block.js.map +1 -0
  84. package/dist/src/mcpl/errors.d.ts +13 -0
  85. package/dist/src/mcpl/errors.d.ts.map +1 -1
  86. package/dist/src/mcpl/errors.js +28 -0
  87. package/dist/src/mcpl/errors.js.map +1 -1
  88. package/dist/src/mcpl/hook-orchestrator.d.ts +23 -0
  89. package/dist/src/mcpl/hook-orchestrator.d.ts.map +1 -1
  90. package/dist/src/mcpl/hook-orchestrator.js +83 -72
  91. package/dist/src/mcpl/hook-orchestrator.js.map +1 -1
  92. package/dist/src/mcpl/inbound-source.d.ts +114 -0
  93. package/dist/src/mcpl/inbound-source.d.ts.map +1 -0
  94. package/dist/src/mcpl/inbound-source.js +83 -0
  95. package/dist/src/mcpl/inbound-source.js.map +1 -0
  96. package/dist/src/mcpl/index.d.ts +7 -1
  97. package/dist/src/mcpl/index.d.ts.map +1 -1
  98. package/dist/src/mcpl/index.js +5 -1
  99. package/dist/src/mcpl/index.js.map +1 -1
  100. package/dist/src/mcpl/inference-router.d.ts +19 -13
  101. package/dist/src/mcpl/inference-router.d.ts.map +1 -1
  102. package/dist/src/mcpl/inference-router.js +155 -87
  103. package/dist/src/mcpl/inference-router.js.map +1 -1
  104. package/dist/src/mcpl/log-value.d.ts +7 -0
  105. package/dist/src/mcpl/log-value.d.ts.map +1 -1
  106. package/dist/src/mcpl/log-value.js +9 -0
  107. package/dist/src/mcpl/log-value.js.map +1 -1
  108. package/dist/src/mcpl/modern-connection.d.ts +227 -0
  109. package/dist/src/mcpl/modern-connection.d.ts.map +1 -0
  110. package/dist/src/mcpl/modern-connection.js +1088 -0
  111. package/dist/src/mcpl/modern-connection.js.map +1 -0
  112. package/dist/src/mcpl/prefix-rule.d.ts +18 -0
  113. package/dist/src/mcpl/prefix-rule.d.ts.map +1 -0
  114. package/dist/src/mcpl/prefix-rule.js +25 -0
  115. package/dist/src/mcpl/prefix-rule.js.map +1 -0
  116. package/dist/src/mcpl/protocol-family.d.ts +179 -0
  117. package/dist/src/mcpl/protocol-family.d.ts.map +1 -0
  118. package/dist/src/mcpl/protocol-family.js +697 -0
  119. package/dist/src/mcpl/protocol-family.js.map +1 -0
  120. package/dist/src/mcpl/push-coalescer.d.ts +58 -17
  121. package/dist/src/mcpl/push-coalescer.d.ts.map +1 -1
  122. package/dist/src/mcpl/push-coalescer.js +93 -32
  123. package/dist/src/mcpl/push-coalescer.js.map +1 -1
  124. package/dist/src/mcpl/push-handler.d.ts +16 -9
  125. package/dist/src/mcpl/push-handler.d.ts.map +1 -1
  126. package/dist/src/mcpl/push-handler.js +18 -83
  127. package/dist/src/mcpl/push-handler.js.map +1 -1
  128. package/dist/src/mcpl/reference-fetcher.d.ts +76 -13
  129. package/dist/src/mcpl/reference-fetcher.d.ts.map +1 -1
  130. package/dist/src/mcpl/reference-fetcher.js +275 -66
  131. package/dist/src/mcpl/reference-fetcher.js.map +1 -1
  132. package/dist/src/mcpl/references.d.ts +98 -18
  133. package/dist/src/mcpl/references.d.ts.map +1 -1
  134. package/dist/src/mcpl/references.js +170 -32
  135. package/dist/src/mcpl/references.js.map +1 -1
  136. package/dist/src/mcpl/server-connection.d.ts +406 -31
  137. package/dist/src/mcpl/server-connection.d.ts.map +1 -1
  138. package/dist/src/mcpl/server-connection.js +1331 -272
  139. package/dist/src/mcpl/server-connection.js.map +1 -1
  140. package/dist/src/mcpl/server-registry.d.ts +35 -6
  141. package/dist/src/mcpl/server-registry.d.ts.map +1 -1
  142. package/dist/src/mcpl/server-registry.js +63 -13
  143. package/dist/src/mcpl/server-registry.js.map +1 -1
  144. package/dist/src/mcpl/skip-reply-wake.d.ts +36 -0
  145. package/dist/src/mcpl/skip-reply-wake.d.ts.map +1 -0
  146. package/dist/src/mcpl/skip-reply-wake.js +55 -0
  147. package/dist/src/mcpl/skip-reply-wake.js.map +1 -0
  148. package/dist/src/mcpl/tool-result-normalize.d.ts +54 -0
  149. package/dist/src/mcpl/tool-result-normalize.d.ts.map +1 -0
  150. package/dist/src/mcpl/tool-result-normalize.js +232 -0
  151. package/dist/src/mcpl/tool-result-normalize.js.map +1 -0
  152. package/dist/src/mcpl/transport.d.ts +104 -12
  153. package/dist/src/mcpl/transport.d.ts.map +1 -1
  154. package/dist/src/mcpl/transport.js +315 -85
  155. package/dist/src/mcpl/transport.js.map +1 -1
  156. package/dist/src/mcpl/types.d.ts +76 -19
  157. package/dist/src/mcpl/types.d.ts.map +1 -1
  158. package/dist/src/mcpl/types.js.map +1 -1
  159. package/dist/src/mcpl/visible-content.d.ts +16 -0
  160. package/dist/src/mcpl/visible-content.d.ts.map +1 -1
  161. package/dist/src/mcpl/visible-content.js +26 -0
  162. package/dist/src/mcpl/visible-content.js.map +1 -1
  163. package/dist/src/module-registry.d.ts +34 -6
  164. package/dist/src/module-registry.d.ts.map +1 -1
  165. package/dist/src/module-registry.js +119 -31
  166. package/dist/src/module-registry.js.map +1 -1
  167. package/dist/src/modules/api/index.d.ts +1 -1
  168. package/dist/src/modules/api/index.d.ts.map +1 -1
  169. package/dist/src/modules/api/index.js +3 -2
  170. package/dist/src/modules/api/index.js.map +1 -1
  171. package/dist/src/modules/discord/discord-js-client.d.ts +43 -2
  172. package/dist/src/modules/discord/discord-js-client.d.ts.map +1 -1
  173. package/dist/src/modules/discord/discord-js-client.js +286 -67
  174. package/dist/src/modules/discord/discord-js-client.js.map +1 -1
  175. package/dist/src/modules/discord/index.d.ts +53 -5
  176. package/dist/src/modules/discord/index.d.ts.map +1 -1
  177. package/dist/src/modules/discord/index.js +712 -186
  178. package/dist/src/modules/discord/index.js.map +1 -1
  179. package/dist/src/modules/discord/refusal.d.ts +14 -0
  180. package/dist/src/modules/discord/refusal.d.ts.map +1 -0
  181. package/dist/src/modules/discord/refusal.js +14 -0
  182. package/dist/src/modules/discord/refusal.js.map +1 -0
  183. package/dist/src/modules/discord/types.d.ts +27 -4
  184. package/dist/src/modules/discord/types.d.ts.map +1 -1
  185. package/dist/src/modules/health/index.d.ts.map +1 -1
  186. package/dist/src/modules/health/index.js +8 -3
  187. package/dist/src/modules/health/index.js.map +1 -1
  188. package/dist/src/modules/history/index.d.ts +3 -1
  189. package/dist/src/modules/history/index.d.ts.map +1 -1
  190. package/dist/src/modules/history/index.js +359 -127
  191. package/dist/src/modules/history/index.js.map +1 -1
  192. package/dist/src/modules/history/semantic.d.ts +28 -1
  193. package/dist/src/modules/history/semantic.d.ts.map +1 -1
  194. package/dist/src/modules/history/semantic.js +177 -32
  195. package/dist/src/modules/history/semantic.js.map +1 -1
  196. package/dist/src/modules/index.d.ts +1 -1
  197. package/dist/src/modules/index.d.ts.map +1 -1
  198. package/dist/src/modules/index.js +1 -1
  199. package/dist/src/modules/index.js.map +1 -1
  200. package/dist/src/modules/unknown-tool.d.ts +10 -0
  201. package/dist/src/modules/unknown-tool.d.ts.map +1 -0
  202. package/dist/src/modules/unknown-tool.js +17 -0
  203. package/dist/src/modules/unknown-tool.js.map +1 -0
  204. package/dist/src/modules/workspace/disk-agreement.d.ts +57 -4
  205. package/dist/src/modules/workspace/disk-agreement.d.ts.map +1 -1
  206. package/dist/src/modules/workspace/disk-agreement.js +75 -7
  207. package/dist/src/modules/workspace/disk-agreement.js.map +1 -1
  208. package/dist/src/modules/workspace/effects.d.ts +66 -7
  209. package/dist/src/modules/workspace/effects.d.ts.map +1 -1
  210. package/dist/src/modules/workspace/effects.js +303 -46
  211. package/dist/src/modules/workspace/effects.js.map +1 -1
  212. package/dist/src/modules/workspace/index.d.ts +313 -45
  213. package/dist/src/modules/workspace/index.d.ts.map +1 -1
  214. package/dist/src/modules/workspace/index.js +1404 -304
  215. package/dist/src/modules/workspace/index.js.map +1 -1
  216. package/dist/src/modules/workspace/observe.d.ts +315 -16
  217. package/dist/src/modules/workspace/observe.d.ts.map +1 -1
  218. package/dist/src/modules/workspace/observe.js +727 -37
  219. package/dist/src/modules/workspace/observe.js.map +1 -1
  220. package/dist/src/modules/workspace/reconcile.d.ts +58 -7
  221. package/dist/src/modules/workspace/reconcile.d.ts.map +1 -1
  222. package/dist/src/modules/workspace/reconcile.js +521 -56
  223. package/dist/src/modules/workspace/reconcile.js.map +1 -1
  224. package/dist/src/modules/workspace/types.d.ts +28 -5
  225. package/dist/src/modules/workspace/types.d.ts.map +1 -1
  226. package/dist/src/modules/workspace/types.js.map +1 -1
  227. package/dist/src/modules/workspace/watcher.d.ts +49 -2
  228. package/dist/src/modules/workspace/watcher.d.ts.map +1 -1
  229. package/dist/src/modules/workspace/watcher.js +158 -29
  230. package/dist/src/modules/workspace/watcher.js.map +1 -1
  231. package/dist/src/prose-drafts.d.ts +240 -0
  232. package/dist/src/prose-drafts.d.ts.map +1 -0
  233. package/dist/src/prose-drafts.js +362 -0
  234. package/dist/src/prose-drafts.js.map +1 -0
  235. package/dist/src/prose-segments.d.ts +21 -2
  236. package/dist/src/prose-segments.d.ts.map +1 -1
  237. package/dist/src/prose-segments.js +46 -9
  238. package/dist/src/prose-segments.js.map +1 -1
  239. package/dist/src/recovery/offline-branch.d.ts +1 -0
  240. package/dist/src/recovery/offline-branch.d.ts.map +1 -1
  241. package/dist/src/recovery/offline-branch.js +3 -1
  242. package/dist/src/recovery/offline-branch.js.map +1 -1
  243. package/dist/src/safe-slice.d.ts +5 -1
  244. package/dist/src/safe-slice.d.ts.map +1 -1
  245. package/dist/src/safe-slice.js +9 -1
  246. package/dist/src/safe-slice.js.map +1 -1
  247. package/dist/src/silent-heartbeat.d.ts +112 -39
  248. package/dist/src/silent-heartbeat.d.ts.map +1 -1
  249. package/dist/src/silent-heartbeat.js +100 -29
  250. package/dist/src/silent-heartbeat.js.map +1 -1
  251. package/dist/src/tool-args.d.ts +40 -0
  252. package/dist/src/tool-args.d.ts.map +1 -0
  253. package/dist/src/tool-args.js +207 -0
  254. package/dist/src/tool-args.js.map +1 -0
  255. package/dist/src/tool-image-ledger.d.ts +87 -19
  256. package/dist/src/tool-image-ledger.d.ts.map +1 -1
  257. package/dist/src/tool-image-ledger.js +135 -32
  258. package/dist/src/tool-image-ledger.js.map +1 -1
  259. package/dist/src/tool-presentation.d.ts +9 -0
  260. package/dist/src/tool-presentation.d.ts.map +1 -1
  261. package/dist/src/tool-presentation.js +266 -62
  262. package/dist/src/tool-presentation.js.map +1 -1
  263. package/dist/src/tool-result-guard.d.ts.map +1 -1
  264. package/dist/src/tool-result-guard.js +7 -10
  265. package/dist/src/tool-result-guard.js.map +1 -1
  266. package/dist/src/tool-result-history.d.ts +32 -3
  267. package/dist/src/tool-result-history.d.ts.map +1 -1
  268. package/dist/src/tool-result-history.js +106 -19
  269. package/dist/src/tool-result-history.js.map +1 -1
  270. package/dist/src/tune-out/coordinator.d.ts +25 -1
  271. package/dist/src/tune-out/coordinator.d.ts.map +1 -1
  272. package/dist/src/tune-out/coordinator.js +260 -65
  273. package/dist/src/tune-out/coordinator.js.map +1 -1
  274. package/dist/src/types/agent.d.ts +44 -22
  275. package/dist/src/types/agent.d.ts.map +1 -1
  276. package/dist/src/types/events.d.ts +25 -0
  277. package/dist/src/types/events.d.ts.map +1 -1
  278. package/dist/src/types/framework.d.ts +38 -7
  279. package/dist/src/types/framework.d.ts.map +1 -1
  280. package/dist/src/types/inference-log.d.ts +1 -1
  281. package/dist/src/types/inference-log.d.ts.map +1 -1
  282. package/dist/src/types/module.d.ts +77 -14
  283. package/dist/src/types/module.d.ts.map +1 -1
  284. package/dist/src/types/trace.d.ts +97 -8
  285. package/dist/src/types/trace.d.ts.map +1 -1
  286. package/dist/src/usage/usage-tracker.d.ts +5 -0
  287. package/dist/src/usage/usage-tracker.d.ts.map +1 -1
  288. package/dist/src/usage/usage-tracker.js +35 -8
  289. package/dist/src/usage/usage-tracker.js.map +1 -1
  290. package/package.json +5 -4
  291. package/src/agent.ts +257 -72
  292. package/src/api/mcp-server-core.ts +1 -1
  293. package/src/api/server.ts +4 -1
  294. package/src/api/types.ts +1 -1
  295. package/src/branch-names.ts +19 -0
  296. package/src/closest-names.ts +94 -0
  297. package/src/code-execution/index.ts +1 -0
  298. package/src/code-execution/py-runner.ts +304 -93
  299. package/src/code-execution/runtime-py.ts +94 -8
  300. package/src/code-execution/tool-definition.ts +85 -7
  301. package/src/config-checks.ts +50 -0
  302. package/src/deadline-timer.ts +44 -0
  303. package/src/error-message.ts +48 -0
  304. package/src/framework.ts +8625 -1984
  305. package/src/gate/event-gate.ts +38 -5
  306. package/src/held-writes.ts +59 -0
  307. package/src/index.ts +29 -5
  308. package/src/mcpl/capability-grant.ts +1 -1
  309. package/src/mcpl/channel-registry.ts +1095 -411
  310. package/src/mcpl/checkpoint-manager.ts +104 -29
  311. package/src/mcpl/conversation-router.ts +28 -8
  312. package/src/mcpl/convert-block.ts +105 -0
  313. package/src/mcpl/errors.ts +28 -0
  314. package/src/mcpl/hook-orchestrator.ts +84 -77
  315. package/src/mcpl/inbound-source.ts +156 -0
  316. package/src/mcpl/index.ts +23 -1
  317. package/src/mcpl/inference-router.ts +179 -103
  318. package/src/mcpl/log-value.ts +10 -0
  319. package/src/mcpl/modern-connection.ts +1182 -0
  320. package/src/mcpl/prefix-rule.ts +32 -0
  321. package/src/mcpl/protocol-family.ts +691 -0
  322. package/src/mcpl/push-coalescer.ts +110 -36
  323. package/src/mcpl/push-handler.ts +20 -90
  324. package/src/mcpl/reference-fetcher.ts +318 -67
  325. package/src/mcpl/references.ts +183 -34
  326. package/src/mcpl/server-connection.ts +1404 -280
  327. package/src/mcpl/server-registry.ts +63 -14
  328. package/src/mcpl/skip-reply-wake.ts +73 -0
  329. package/src/mcpl/tool-result-normalize.ts +294 -0
  330. package/src/mcpl/transport.ts +320 -76
  331. package/src/mcpl/types.ts +77 -19
  332. package/src/mcpl/visible-content.ts +28 -0
  333. package/src/module-registry.ts +126 -36
  334. package/src/modules/api/index.ts +3 -2
  335. package/src/modules/discord/discord-js-client.ts +306 -74
  336. package/src/modules/discord/index.ts +737 -201
  337. package/src/modules/discord/refusal.ts +13 -0
  338. package/src/modules/discord/types.ts +27 -6
  339. package/src/modules/health/index.ts +8 -3
  340. package/src/modules/history/index.ts +410 -120
  341. package/src/modules/history/semantic.ts +189 -32
  342. package/src/modules/index.ts +1 -1
  343. package/src/modules/unknown-tool.ts +16 -0
  344. package/src/modules/workspace/disk-agreement.ts +97 -8
  345. package/src/modules/workspace/effects.ts +291 -36
  346. package/src/modules/workspace/index.ts +1469 -321
  347. package/src/modules/workspace/observe.ts +784 -41
  348. package/src/modules/workspace/reconcile.ts +619 -64
  349. package/src/modules/workspace/types.ts +28 -5
  350. package/src/modules/workspace/watcher.ts +154 -30
  351. package/src/prose-drafts.ts +481 -0
  352. package/src/prose-segments.ts +51 -8
  353. package/src/recovery/offline-branch.ts +4 -1
  354. package/src/safe-slice.ts +9 -1
  355. package/src/silent-heartbeat.ts +184 -59
  356. package/src/tool-args.ts +213 -0
  357. package/src/tool-image-ledger.ts +153 -34
  358. package/src/tool-presentation.ts +233 -42
  359. package/src/tool-result-guard.ts +7 -8
  360. package/src/tool-result-history.ts +124 -20
  361. package/src/tune-out/coordinator.ts +259 -65
  362. package/src/types/agent.ts +44 -24
  363. package/src/types/events.ts +25 -0
  364. package/src/types/framework.ts +38 -7
  365. package/src/types/inference-log.ts +1 -1
  366. package/src/types/module.ts +79 -14
  367. package/src/types/trace.ts +103 -8
  368. package/src/usage/usage-tracker.ts +32 -8
  369. package/dist/test/activation-request-sanitize.test.d.ts +0 -2
  370. package/dist/test/activation-request-sanitize.test.d.ts.map +0 -1
  371. package/dist/test/activation-request-sanitize.test.js +0 -89
  372. package/dist/test/activation-request-sanitize.test.js.map +0 -1
  373. package/dist/test/agent-cache-ttl.test.d.ts +0 -2
  374. package/dist/test/agent-cache-ttl.test.d.ts.map +0 -1
  375. package/dist/test/agent-cache-ttl.test.js +0 -41
  376. package/dist/test/agent-cache-ttl.test.js.map +0 -1
  377. package/dist/test/agent-runtime-settings.test.d.ts +0 -2
  378. package/dist/test/agent-runtime-settings.test.d.ts.map +0 -1
  379. package/dist/test/agent-runtime-settings.test.js +0 -1598
  380. package/dist/test/agent-runtime-settings.test.js.map +0 -1
  381. package/dist/test/api-admin-gate.test.d.ts +0 -2
  382. package/dist/test/api-admin-gate.test.d.ts.map +0 -1
  383. package/dist/test/api-admin-gate.test.js +0 -116
  384. package/dist/test/api-admin-gate.test.js.map +0 -1
  385. package/dist/test/assistant-persist-refusal.test.d.ts +0 -2
  386. package/dist/test/assistant-persist-refusal.test.d.ts.map +0 -1
  387. package/dist/test/assistant-persist-refusal.test.js +0 -63
  388. package/dist/test/assistant-persist-refusal.test.js.map +0 -1
  389. package/dist/test/batched-wake-locus.test.d.ts +0 -2
  390. package/dist/test/batched-wake-locus.test.d.ts.map +0 -1
  391. package/dist/test/batched-wake-locus.test.js +0 -166
  392. package/dist/test/batched-wake-locus.test.js.map +0 -1
  393. package/dist/test/busy-agent-scheduler.test.d.ts +0 -2
  394. package/dist/test/busy-agent-scheduler.test.d.ts.map +0 -1
  395. package/dist/test/busy-agent-scheduler.test.js +0 -92
  396. package/dist/test/busy-agent-scheduler.test.js.map +0 -1
  397. package/dist/test/channel-incoming-targeting.test.d.ts +0 -2
  398. package/dist/test/channel-incoming-targeting.test.d.ts.map +0 -1
  399. package/dist/test/channel-incoming-targeting.test.js +0 -81
  400. package/dist/test/channel-incoming-targeting.test.js.map +0 -1
  401. package/dist/test/channel-label-history.test.d.ts +0 -2
  402. package/dist/test/channel-label-history.test.d.ts.map +0 -1
  403. package/dist/test/channel-label-history.test.js +0 -424
  404. package/dist/test/channel-label-history.test.js.map +0 -1
  405. package/dist/test/channel-lifecycle-provenance.test.d.ts +0 -2
  406. package/dist/test/channel-lifecycle-provenance.test.d.ts.map +0 -1
  407. package/dist/test/channel-lifecycle-provenance.test.js +0 -47
  408. package/dist/test/channel-lifecycle-provenance.test.js.map +0 -1
  409. package/dist/test/channel-registry-routing.test.d.ts +0 -2
  410. package/dist/test/channel-registry-routing.test.d.ts.map +0 -1
  411. package/dist/test/channel-registry-routing.test.js +0 -446
  412. package/dist/test/channel-registry-routing.test.js.map +0 -1
  413. package/dist/test/channel-registry-typing.test.d.ts +0 -2
  414. package/dist/test/channel-registry-typing.test.d.ts.map +0 -1
  415. package/dist/test/channel-registry-typing.test.js +0 -91
  416. package/dist/test/channel-registry-typing.test.js.map +0 -1
  417. package/dist/test/channels-changed-respond-first.test.d.ts +0 -2
  418. package/dist/test/channels-changed-respond-first.test.d.ts.map +0 -1
  419. package/dist/test/channels-changed-respond-first.test.js +0 -74
  420. package/dist/test/channels-changed-respond-first.test.js.map +0 -1
  421. package/dist/test/checkpoint-attribution.test.d.ts +0 -2
  422. package/dist/test/checkpoint-attribution.test.d.ts.map +0 -1
  423. package/dist/test/checkpoint-attribution.test.js +0 -200
  424. package/dist/test/checkpoint-attribution.test.js.map +0 -1
  425. package/dist/test/code-execution.test.d.ts +0 -11
  426. package/dist/test/code-execution.test.d.ts.map +0 -1
  427. package/dist/test/code-execution.test.js +0 -1272
  428. package/dist/test/code-execution.test.js.map +0 -1
  429. package/dist/test/component-defaults.test.d.ts +0 -2
  430. package/dist/test/component-defaults.test.d.ts.map +0 -1
  431. package/dist/test/component-defaults.test.js +0 -54
  432. package/dist/test/component-defaults.test.js.map +0 -1
  433. package/dist/test/conversation-fork-injection-scoping.test.d.ts +0 -2
  434. package/dist/test/conversation-fork-injection-scoping.test.d.ts.map +0 -1
  435. package/dist/test/conversation-fork-injection-scoping.test.js +0 -200
  436. package/dist/test/conversation-fork-injection-scoping.test.js.map +0 -1
  437. package/dist/test/conversation-router.test.d.ts +0 -2
  438. package/dist/test/conversation-router.test.d.ts.map +0 -1
  439. package/dist/test/conversation-router.test.js +0 -174
  440. package/dist/test/conversation-router.test.js.map +0 -1
  441. package/dist/test/conversation-routing.test.d.ts +0 -7
  442. package/dist/test/conversation-routing.test.d.ts.map +0 -1
  443. package/dist/test/conversation-routing.test.js +0 -621
  444. package/dist/test/conversation-routing.test.js.map +0 -1
  445. package/dist/test/deferred-wake-integrity.test.d.ts +0 -29
  446. package/dist/test/deferred-wake-integrity.test.d.ts.map +0 -1
  447. package/dist/test/deferred-wake-integrity.test.js +0 -320
  448. package/dist/test/deferred-wake-integrity.test.js.map +0 -1
  449. package/dist/test/discord-awareness-outbox.test.d.ts +0 -2
  450. package/dist/test/discord-awareness-outbox.test.d.ts.map +0 -1
  451. package/dist/test/discord-awareness-outbox.test.js +0 -371
  452. package/dist/test/discord-awareness-outbox.test.js.map +0 -1
  453. package/dist/test/discord-history-delete-window.test.d.ts +0 -2
  454. package/dist/test/discord-history-delete-window.test.d.ts.map +0 -1
  455. package/dist/test/discord-history-delete-window.test.js +0 -81
  456. package/dist/test/discord-history-delete-window.test.js.map +0 -1
  457. package/dist/test/discord-history-sync.test.d.ts +0 -2
  458. package/dist/test/discord-history-sync.test.d.ts.map +0 -1
  459. package/dist/test/discord-history-sync.test.js +0 -56
  460. package/dist/test/discord-history-sync.test.js.map +0 -1
  461. package/dist/test/discord-typing-keepalive.test.d.ts +0 -2
  462. package/dist/test/discord-typing-keepalive.test.d.ts.map +0 -1
  463. package/dist/test/discord-typing-keepalive.test.js +0 -77
  464. package/dist/test/discord-typing-keepalive.test.js.map +0 -1
  465. package/dist/test/ephemeral-settle.test.d.ts +0 -2
  466. package/dist/test/ephemeral-settle.test.d.ts.map +0 -1
  467. package/dist/test/ephemeral-settle.test.js +0 -354
  468. package/dist/test/ephemeral-settle.test.js.map +0 -1
  469. package/dist/test/event-gate-passthrough.test.d.ts +0 -15
  470. package/dist/test/event-gate-passthrough.test.d.ts.map +0 -1
  471. package/dist/test/event-gate-passthrough.test.js +0 -289
  472. package/dist/test/event-gate-passthrough.test.js.map +0 -1
  473. package/dist/test/event-gate-policy-mutation.test.d.ts +0 -2
  474. package/dist/test/event-gate-policy-mutation.test.d.ts.map +0 -1
  475. package/dist/test/event-gate-policy-mutation.test.js +0 -137
  476. package/dist/test/event-gate-policy-mutation.test.js.map +0 -1
  477. package/dist/test/event-gate-rate-limit.test.d.ts +0 -2
  478. package/dist/test/event-gate-rate-limit.test.d.ts.map +0 -1
  479. package/dist/test/event-gate-rate-limit.test.js +0 -627
  480. package/dist/test/event-gate-rate-limit.test.js.map +0 -1
  481. package/dist/test/event-gate-script.test.d.ts +0 -2
  482. package/dist/test/event-gate-script.test.d.ts.map +0 -1
  483. package/dist/test/event-gate-script.test.js +0 -95
  484. package/dist/test/event-gate-script.test.js.map +0 -1
  485. package/dist/test/event-gate-selfwake.test.d.ts +0 -15
  486. package/dist/test/event-gate-selfwake.test.d.ts.map +0 -1
  487. package/dist/test/event-gate-selfwake.test.js +0 -125
  488. package/dist/test/event-gate-selfwake.test.js.map +0 -1
  489. package/dist/test/event-gate-tags.test.d.ts +0 -2
  490. package/dist/test/event-gate-tags.test.d.ts.map +0 -1
  491. package/dist/test/event-gate-tags.test.js +0 -76
  492. package/dist/test/event-gate-tags.test.js.map +0 -1
  493. package/dist/test/event-gate.test.d.ts +0 -2
  494. package/dist/test/event-gate.test.d.ts.map +0 -1
  495. package/dist/test/event-gate.test.js +0 -919
  496. package/dist/test/event-gate.test.js.map +0 -1
  497. package/dist/test/explicit-prose-routing.test.d.ts +0 -11
  498. package/dist/test/explicit-prose-routing.test.d.ts.map +0 -1
  499. package/dist/test/explicit-prose-routing.test.js +0 -1715
  500. package/dist/test/explicit-prose-routing.test.js.map +0 -1
  501. package/dist/test/framework.test.d.ts +0 -5
  502. package/dist/test/framework.test.d.ts.map +0 -1
  503. package/dist/test/framework.test.js +0 -1048
  504. package/dist/test/framework.test.js.map +0 -1
  505. package/dist/test/gather-context-timeout.test.d.ts +0 -2
  506. package/dist/test/gather-context-timeout.test.d.ts.map +0 -1
  507. package/dist/test/gather-context-timeout.test.js +0 -120
  508. package/dist/test/gather-context-timeout.test.js.map +0 -1
  509. package/dist/test/health-snapshot.test.d.ts +0 -2
  510. package/dist/test/health-snapshot.test.d.ts.map +0 -1
  511. package/dist/test/health-snapshot.test.js +0 -74
  512. package/dist/test/health-snapshot.test.js.map +0 -1
  513. package/dist/test/helpers/coalescing-fixture.d.ts +0 -74
  514. package/dist/test/helpers/coalescing-fixture.d.ts.map +0 -1
  515. package/dist/test/helpers/coalescing-fixture.js +0 -152
  516. package/dist/test/helpers/coalescing-fixture.js.map +0 -1
  517. package/dist/test/helpers/coalescing-kill-child.d.ts +0 -2
  518. package/dist/test/helpers/coalescing-kill-child.d.ts.map +0 -1
  519. package/dist/test/helpers/coalescing-kill-child.js +0 -24
  520. package/dist/test/helpers/coalescing-kill-child.js.map +0 -1
  521. package/dist/test/helpers/mock-membrane.d.ts +0 -53
  522. package/dist/test/helpers/mock-membrane.d.ts.map +0 -1
  523. package/dist/test/helpers/mock-membrane.js +0 -168
  524. package/dist/test/helpers/mock-membrane.js.map +0 -1
  525. package/dist/test/helpers/pytc-stop-rows.d.ts +0 -11
  526. package/dist/test/helpers/pytc-stop-rows.d.ts.map +0 -1
  527. package/dist/test/helpers/pytc-stop-rows.js +0 -143
  528. package/dist/test/helpers/pytc-stop-rows.js.map +0 -1
  529. package/dist/test/helpers/quiesce-crash-child.d.ts +0 -2
  530. package/dist/test/helpers/quiesce-crash-child.d.ts.map +0 -1
  531. package/dist/test/helpers/quiesce-crash-child.js +0 -156
  532. package/dist/test/helpers/quiesce-crash-child.js.map +0 -1
  533. package/dist/test/hide-then-turn.test.d.ts +0 -2
  534. package/dist/test/hide-then-turn.test.d.ts.map +0 -1
  535. package/dist/test/hide-then-turn.test.js +0 -101
  536. package/dist/test/hide-then-turn.test.js.map +0 -1
  537. package/dist/test/history-module-overview.test.d.ts +0 -2
  538. package/dist/test/history-module-overview.test.d.ts.map +0 -1
  539. package/dist/test/history-module-overview.test.js +0 -711
  540. package/dist/test/history-module-overview.test.js.map +0 -1
  541. package/dist/test/history-module-realstore.test.d.ts +0 -2
  542. package/dist/test/history-module-realstore.test.d.ts.map +0 -1
  543. package/dist/test/history-module-realstore.test.js +0 -363
  544. package/dist/test/history-module-realstore.test.js.map +0 -1
  545. package/dist/test/history-module-semantic.test.d.ts +0 -2
  546. package/dist/test/history-module-semantic.test.d.ts.map +0 -1
  547. package/dist/test/history-module-semantic.test.js +0 -213
  548. package/dist/test/history-module-semantic.test.js.map +0 -1
  549. package/dist/test/history-module-ux.test.d.ts +0 -2
  550. package/dist/test/history-module-ux.test.d.ts.map +0 -1
  551. package/dist/test/history-module-ux.test.js +0 -304
  552. package/dist/test/history-module-ux.test.js.map +0 -1
  553. package/dist/test/history-module.test.d.ts +0 -2
  554. package/dist/test/history-module.test.d.ts.map +0 -1
  555. package/dist/test/history-module.test.js +0 -619
  556. package/dist/test/history-module.test.js.map +0 -1
  557. package/dist/test/history-semantic-review-findings.test.d.ts +0 -2
  558. package/dist/test/history-semantic-review-findings.test.d.ts.map +0 -1
  559. package/dist/test/history-semantic-review-findings.test.js +0 -338
  560. package/dist/test/history-semantic-review-findings.test.js.map +0 -1
  561. package/dist/test/history-semantic-sync-converges.test.d.ts +0 -2
  562. package/dist/test/history-semantic-sync-converges.test.d.ts.map +0 -1
  563. package/dist/test/history-semantic-sync-converges.test.js +0 -109
  564. package/dist/test/history-semantic-sync-converges.test.js.map +0 -1
  565. package/dist/test/host-quiesce.test.d.ts +0 -2
  566. package/dist/test/host-quiesce.test.d.ts.map +0 -1
  567. package/dist/test/host-quiesce.test.js +0 -988
  568. package/dist/test/host-quiesce.test.js.map +0 -1
  569. package/dist/test/inference-exhaustion-rewind.test.d.ts +0 -2
  570. package/dist/test/inference-exhaustion-rewind.test.d.ts.map +0 -1
  571. package/dist/test/inference-exhaustion-rewind.test.js +0 -387
  572. package/dist/test/inference-exhaustion-rewind.test.js.map +0 -1
  573. package/dist/test/inference-failure-bounds.test.d.ts +0 -2
  574. package/dist/test/inference-failure-bounds.test.d.ts.map +0 -1
  575. package/dist/test/inference-failure-bounds.test.js +0 -1202
  576. package/dist/test/inference-failure-bounds.test.js.map +0 -1
  577. package/dist/test/inference-failure-observability.test.d.ts +0 -2
  578. package/dist/test/inference-failure-observability.test.d.ts.map +0 -1
  579. package/dist/test/inference-failure-observability.test.js +0 -84
  580. package/dist/test/inference-failure-observability.test.js.map +0 -1
  581. package/dist/test/journal-tool.test.d.ts +0 -2
  582. package/dist/test/journal-tool.test.d.ts.map +0 -1
  583. package/dist/test/journal-tool.test.js +0 -33
  584. package/dist/test/journal-tool.test.js.map +0 -1
  585. package/dist/test/kv-unified-open-flight-retry.test.d.ts +0 -2
  586. package/dist/test/kv-unified-open-flight-retry.test.d.ts.map +0 -1
  587. package/dist/test/kv-unified-open-flight-retry.test.js +0 -189
  588. package/dist/test/kv-unified-open-flight-retry.test.js.map +0 -1
  589. package/dist/test/kv-unified-wiring.test.d.ts +0 -2
  590. package/dist/test/kv-unified-wiring.test.d.ts.map +0 -1
  591. package/dist/test/kv-unified-wiring.test.js +0 -95
  592. package/dist/test/kv-unified-wiring.test.js.map +0 -1
  593. package/dist/test/late-events-after-stop.test.d.ts +0 -2
  594. package/dist/test/late-events-after-stop.test.d.ts.map +0 -1
  595. package/dist/test/late-events-after-stop.test.js +0 -122
  596. package/dist/test/late-events-after-stop.test.js.map +0 -1
  597. package/dist/test/liveness-watchdog.test.d.ts +0 -2
  598. package/dist/test/liveness-watchdog.test.d.ts.map +0 -1
  599. package/dist/test/liveness-watchdog.test.js +0 -94
  600. package/dist/test/liveness-watchdog.test.js.map +0 -1
  601. package/dist/test/machine-close-provenance.test.d.ts +0 -2
  602. package/dist/test/machine-close-provenance.test.d.ts.map +0 -1
  603. package/dist/test/machine-close-provenance.test.js +0 -116
  604. package/dist/test/machine-close-provenance.test.js.map +0 -1
  605. package/dist/test/maintenance-timer.test.d.ts +0 -2
  606. package/dist/test/maintenance-timer.test.d.ts.map +0 -1
  607. package/dist/test/maintenance-timer.test.js +0 -1827
  608. package/dist/test/maintenance-timer.test.js.map +0 -1
  609. package/dist/test/mcp-server-bin.test.d.ts +0 -2
  610. package/dist/test/mcp-server-bin.test.d.ts.map +0 -1
  611. package/dist/test/mcp-server-bin.test.js +0 -142
  612. package/dist/test/mcp-server-bin.test.js.map +0 -1
  613. package/dist/test/mcpl-access-provider.test.d.ts +0 -2
  614. package/dist/test/mcpl-access-provider.test.d.ts.map +0 -1
  615. package/dist/test/mcpl-access-provider.test.js +0 -20
  616. package/dist/test/mcpl-access-provider.test.js.map +0 -1
  617. package/dist/test/mcpl-awareness-barrier.test.d.ts +0 -2
  618. package/dist/test/mcpl-awareness-barrier.test.d.ts.map +0 -1
  619. package/dist/test/mcpl-awareness-barrier.test.js +0 -769
  620. package/dist/test/mcpl-awareness-barrier.test.js.map +0 -1
  621. package/dist/test/mcpl-capability-grant.test.d.ts +0 -10
  622. package/dist/test/mcpl-capability-grant.test.d.ts.map +0 -1
  623. package/dist/test/mcpl-capability-grant.test.js +0 -111
  624. package/dist/test/mcpl-capability-grant.test.js.map +0 -1
  625. package/dist/test/mcpl-capability-scoping.test.d.ts +0 -2
  626. package/dist/test/mcpl-capability-scoping.test.d.ts.map +0 -1
  627. package/dist/test/mcpl-capability-scoping.test.js +0 -266
  628. package/dist/test/mcpl-capability-scoping.test.js.map +0 -1
  629. package/dist/test/mcpl-child-env.test.d.ts +0 -2
  630. package/dist/test/mcpl-child-env.test.d.ts.map +0 -1
  631. package/dist/test/mcpl-child-env.test.js +0 -158
  632. package/dist/test/mcpl-child-env.test.js.map +0 -1
  633. package/dist/test/mcpl-coalesced-content-parity.test.d.ts +0 -2
  634. package/dist/test/mcpl-coalesced-content-parity.test.d.ts.map +0 -1
  635. package/dist/test/mcpl-coalesced-content-parity.test.js +0 -532
  636. package/dist/test/mcpl-coalesced-content-parity.test.js.map +0 -1
  637. package/dist/test/mcpl-coalescing.test.d.ts +0 -2
  638. package/dist/test/mcpl-coalescing.test.d.ts.map +0 -1
  639. package/dist/test/mcpl-coalescing.test.js +0 -1125
  640. package/dist/test/mcpl-coalescing.test.js.map +0 -1
  641. package/dist/test/mcpl-config-diagnostics.test.d.ts +0 -2
  642. package/dist/test/mcpl-config-diagnostics.test.d.ts.map +0 -1
  643. package/dist/test/mcpl-config-diagnostics.test.js +0 -452
  644. package/dist/test/mcpl-config-diagnostics.test.js.map +0 -1
  645. package/dist/test/mcpl-empty-content.test.d.ts +0 -2
  646. package/dist/test/mcpl-empty-content.test.d.ts.map +0 -1
  647. package/dist/test/mcpl-empty-content.test.js +0 -368
  648. package/dist/test/mcpl-empty-content.test.js.map +0 -1
  649. package/dist/test/mcpl-gate-roundtrip.test.d.ts +0 -2
  650. package/dist/test/mcpl-gate-roundtrip.test.d.ts.map +0 -1
  651. package/dist/test/mcpl-gate-roundtrip.test.js +0 -285
  652. package/dist/test/mcpl-gate-roundtrip.test.js.map +0 -1
  653. package/dist/test/mcpl-list-status.test.d.ts +0 -2
  654. package/dist/test/mcpl-list-status.test.d.ts.map +0 -1
  655. package/dist/test/mcpl-list-status.test.js +0 -82
  656. package/dist/test/mcpl-list-status.test.js.map +0 -1
  657. package/dist/test/mcpl-manifest-changed.test.d.ts +0 -2
  658. package/dist/test/mcpl-manifest-changed.test.d.ts.map +0 -1
  659. package/dist/test/mcpl-manifest-changed.test.js +0 -178
  660. package/dist/test/mcpl-manifest-changed.test.js.map +0 -1
  661. package/dist/test/mcpl-push-convert.test.d.ts +0 -2
  662. package/dist/test/mcpl-push-convert.test.d.ts.map +0 -1
  663. package/dist/test/mcpl-push-convert.test.js +0 -42
  664. package/dist/test/mcpl-push-convert.test.js.map +0 -1
  665. package/dist/test/mcpl-reconnect-events.test.d.ts +0 -2
  666. package/dist/test/mcpl-reconnect-events.test.d.ts.map +0 -1
  667. package/dist/test/mcpl-reconnect-events.test.js +0 -144
  668. package/dist/test/mcpl-reconnect-events.test.js.map +0 -1
  669. package/dist/test/mcpl-reconnect-reregistration.test.d.ts +0 -2
  670. package/dist/test/mcpl-reconnect-reregistration.test.d.ts.map +0 -1
  671. package/dist/test/mcpl-reconnect-reregistration.test.js +0 -238
  672. package/dist/test/mcpl-reconnect-reregistration.test.js.map +0 -1
  673. package/dist/test/mcpl-reference-fetcher.test.d.ts +0 -2
  674. package/dist/test/mcpl-reference-fetcher.test.d.ts.map +0 -1
  675. package/dist/test/mcpl-reference-fetcher.test.js +0 -427
  676. package/dist/test/mcpl-reference-fetcher.test.js.map +0 -1
  677. package/dist/test/mcpl-reference-fields.test.d.ts +0 -2
  678. package/dist/test/mcpl-reference-fields.test.d.ts.map +0 -1
  679. package/dist/test/mcpl-reference-fields.test.js +0 -149
  680. package/dist/test/mcpl-reference-fields.test.js.map +0 -1
  681. package/dist/test/mcpl-rejection-log-lines.test.d.ts +0 -2
  682. package/dist/test/mcpl-rejection-log-lines.test.d.ts.map +0 -1
  683. package/dist/test/mcpl-rejection-log-lines.test.js +0 -349
  684. package/dist/test/mcpl-rejection-log-lines.test.js.map +0 -1
  685. package/dist/test/mcpl-request-timeout.test.d.ts +0 -2
  686. package/dist/test/mcpl-request-timeout.test.d.ts.map +0 -1
  687. package/dist/test/mcpl-request-timeout.test.js +0 -138
  688. package/dist/test/mcpl-request-timeout.test.js.map +0 -1
  689. package/dist/test/mcpl-runtime-lifecycle.test.d.ts +0 -7
  690. package/dist/test/mcpl-runtime-lifecycle.test.d.ts.map +0 -1
  691. package/dist/test/mcpl-runtime-lifecycle.test.js +0 -142
  692. package/dist/test/mcpl-runtime-lifecycle.test.js.map +0 -1
  693. package/dist/test/mcpl-stderr-tail.test.d.ts +0 -2
  694. package/dist/test/mcpl-stderr-tail.test.d.ts.map +0 -1
  695. package/dist/test/mcpl-stderr-tail.test.js +0 -210
  696. package/dist/test/mcpl-stderr-tail.test.js.map +0 -1
  697. package/dist/test/mcpl-tool-class-listing.test.d.ts +0 -2
  698. package/dist/test/mcpl-tool-class-listing.test.d.ts.map +0 -1
  699. package/dist/test/mcpl-tool-class-listing.test.js +0 -147
  700. package/dist/test/mcpl-tool-class-listing.test.js.map +0 -1
  701. package/dist/test/mcpl-tool-classes.test.d.ts +0 -7
  702. package/dist/test/mcpl-tool-classes.test.d.ts.map +0 -1
  703. package/dist/test/mcpl-tool-classes.test.js +0 -80
  704. package/dist/test/mcpl-tool-classes.test.js.map +0 -1
  705. package/dist/test/mcpl-tool-lifecycle-e2e.test.d.ts +0 -2
  706. package/dist/test/mcpl-tool-lifecycle-e2e.test.d.ts.map +0 -1
  707. package/dist/test/mcpl-tool-lifecycle-e2e.test.js +0 -237
  708. package/dist/test/mcpl-tool-lifecycle-e2e.test.js.map +0 -1
  709. package/dist/test/mcpl-tool-lifecycle-emitter.test.d.ts +0 -11
  710. package/dist/test/mcpl-tool-lifecycle-emitter.test.d.ts.map +0 -1
  711. package/dist/test/mcpl-tool-lifecycle-emitter.test.js +0 -412
  712. package/dist/test/mcpl-tool-lifecycle-emitter.test.js.map +0 -1
  713. package/dist/test/mcpl-tool-lifecycle-script.test.d.ts +0 -2
  714. package/dist/test/mcpl-tool-lifecycle-script.test.d.ts.map +0 -1
  715. package/dist/test/mcpl-tool-lifecycle-script.test.js +0 -288
  716. package/dist/test/mcpl-tool-lifecycle-script.test.js.map +0 -1
  717. package/dist/test/mcpl-tool-lifecycle.test.d.ts +0 -11
  718. package/dist/test/mcpl-tool-lifecycle.test.d.ts.map +0 -1
  719. package/dist/test/mcpl-tool-lifecycle.test.js +0 -270
  720. package/dist/test/mcpl-tool-lifecycle.test.js.map +0 -1
  721. package/dist/test/mcpl-transport-close.test.d.ts +0 -2
  722. package/dist/test/mcpl-transport-close.test.d.ts.map +0 -1
  723. package/dist/test/mcpl-transport-close.test.js +0 -373
  724. package/dist/test/mcpl-transport-close.test.js.map +0 -1
  725. package/dist/test/mcpl-transport-spawn.test.d.ts +0 -2
  726. package/dist/test/mcpl-transport-spawn.test.d.ts.map +0 -1
  727. package/dist/test/mcpl-transport-spawn.test.js +0 -58
  728. package/dist/test/mcpl-transport-spawn.test.js.map +0 -1
  729. package/dist/test/mcpl-ws-transport.test.d.ts +0 -2
  730. package/dist/test/mcpl-ws-transport.test.d.ts.map +0 -1
  731. package/dist/test/mcpl-ws-transport.test.js +0 -259
  732. package/dist/test/mcpl-ws-transport.test.js.map +0 -1
  733. package/dist/test/module-context-integration.test.d.ts +0 -18
  734. package/dist/test/module-context-integration.test.d.ts.map +0 -1
  735. package/dist/test/module-context-integration.test.js +0 -181
  736. package/dist/test/module-context-integration.test.js.map +0 -1
  737. package/dist/test/offline-recovery-branch.test.d.ts +0 -2
  738. package/dist/test/offline-recovery-branch.test.d.ts.map +0 -1
  739. package/dist/test/offline-recovery-branch.test.js +0 -570
  740. package/dist/test/offline-recovery-branch.test.js.map +0 -1
  741. package/dist/test/operator-surgery.test.d.ts +0 -2
  742. package/dist/test/operator-surgery.test.d.ts.map +0 -1
  743. package/dist/test/operator-surgery.test.js +0 -595
  744. package/dist/test/operator-surgery.test.js.map +0 -1
  745. package/dist/test/ops-alert.test.d.ts +0 -2
  746. package/dist/test/ops-alert.test.d.ts.map +0 -1
  747. package/dist/test/ops-alert.test.js +0 -153
  748. package/dist/test/ops-alert.test.js.map +0 -1
  749. package/dist/test/overbudget-drain-breaker.test.d.ts +0 -2
  750. package/dist/test/overbudget-drain-breaker.test.d.ts.map +0 -1
  751. package/dist/test/overbudget-drain-breaker.test.js +0 -198
  752. package/dist/test/overbudget-drain-breaker.test.js.map +0 -1
  753. package/dist/test/pack-installs-alone.test.d.ts +0 -2
  754. package/dist/test/pack-installs-alone.test.d.ts.map +0 -1
  755. package/dist/test/pack-installs-alone.test.js +0 -284
  756. package/dist/test/pack-installs-alone.test.js.map +0 -1
  757. package/dist/test/per-agent-delivery.test.d.ts +0 -2
  758. package/dist/test/per-agent-delivery.test.d.ts.map +0 -1
  759. package/dist/test/per-agent-delivery.test.js +0 -108
  760. package/dist/test/per-agent-delivery.test.js.map +0 -1
  761. package/dist/test/physical-window-restart.test.d.ts +0 -16
  762. package/dist/test/physical-window-restart.test.d.ts.map +0 -1
  763. package/dist/test/physical-window-restart.test.js +0 -487
  764. package/dist/test/physical-window-restart.test.js.map +0 -1
  765. package/dist/test/placed-reaction-baseline.test.d.ts +0 -2
  766. package/dist/test/placed-reaction-baseline.test.d.ts.map +0 -1
  767. package/dist/test/placed-reaction-baseline.test.js +0 -312
  768. package/dist/test/placed-reaction-baseline.test.js.map +0 -1
  769. package/dist/test/present-while-acting.test.d.ts +0 -19
  770. package/dist/test/present-while-acting.test.d.ts.map +0 -1
  771. package/dist/test/present-while-acting.test.js +0 -1649
  772. package/dist/test/present-while-acting.test.js.map +0 -1
  773. package/dist/test/prose-segments.test.d.ts +0 -2
  774. package/dist/test/prose-segments.test.d.ts.map +0 -1
  775. package/dist/test/prose-segments.test.js +0 -52
  776. package/dist/test/prose-segments.test.js.map +0 -1
  777. package/dist/test/prose-stream-router.test.d.ts +0 -2
  778. package/dist/test/prose-stream-router.test.d.ts.map +0 -1
  779. package/dist/test/prose-stream-router.test.js +0 -171
  780. package/dist/test/prose-stream-router.test.js.map +0 -1
  781. package/dist/test/provider-acceleration-cooldown.test.d.ts +0 -2
  782. package/dist/test/provider-acceleration-cooldown.test.d.ts.map +0 -1
  783. package/dist/test/provider-acceleration-cooldown.test.js +0 -435
  784. package/dist/test/provider-acceleration-cooldown.test.js.map +0 -1
  785. package/dist/test/provider-waits.test.d.ts +0 -2
  786. package/dist/test/provider-waits.test.d.ts.map +0 -1
  787. package/dist/test/provider-waits.test.js +0 -2259
  788. package/dist/test/provider-waits.test.js.map +0 -1
  789. package/dist/test/puppet-tool-call.test.d.ts +0 -2
  790. package/dist/test/puppet-tool-call.test.d.ts.map +0 -1
  791. package/dist/test/puppet-tool-call.test.js +0 -226
  792. package/dist/test/puppet-tool-call.test.js.map +0 -1
  793. package/dist/test/puppet-turn-reservation.test.d.ts +0 -2
  794. package/dist/test/puppet-turn-reservation.test.d.ts.map +0 -1
  795. package/dist/test/puppet-turn-reservation.test.js +0 -139
  796. package/dist/test/puppet-turn-reservation.test.js.map +0 -1
  797. package/dist/test/reaction-baseline-platform.test.d.ts +0 -2
  798. package/dist/test/reaction-baseline-platform.test.d.ts.map +0 -1
  799. package/dist/test/reaction-baseline-platform.test.js +0 -124
  800. package/dist/test/reaction-baseline-platform.test.js.map +0 -1
  801. package/dist/test/record-journal.test.d.ts +0 -6
  802. package/dist/test/record-journal.test.d.ts.map +0 -1
  803. package/dist/test/record-journal.test.js +0 -269
  804. package/dist/test/record-journal.test.js.map +0 -1
  805. package/dist/test/refusal-reaction-baseline.test.d.ts +0 -2
  806. package/dist/test/refusal-reaction-baseline.test.d.ts.map +0 -1
  807. package/dist/test/refusal-reaction-baseline.test.js +0 -81
  808. package/dist/test/refusal-reaction-baseline.test.js.map +0 -1
  809. package/dist/test/refusal-rewind.test.d.ts +0 -2
  810. package/dist/test/refusal-rewind.test.d.ts.map +0 -1
  811. package/dist/test/refusal-rewind.test.js +0 -117
  812. package/dist/test/refusal-rewind.test.js.map +0 -1
  813. package/dist/test/refusal-single-call.test.d.ts +0 -2
  814. package/dist/test/refusal-single-call.test.d.ts.map +0 -1
  815. package/dist/test/refusal-single-call.test.js +0 -177
  816. package/dist/test/refusal-single-call.test.js.map +0 -1
  817. package/dist/test/release-bump.test.d.ts +0 -2
  818. package/dist/test/release-bump.test.d.ts.map +0 -1
  819. package/dist/test/release-bump.test.js +0 -248
  820. package/dist/test/release-bump.test.js.map +0 -1
  821. package/dist/test/release-changelog.test.d.ts +0 -2
  822. package/dist/test/release-changelog.test.d.ts.map +0 -1
  823. package/dist/test/release-changelog.test.js +0 -159
  824. package/dist/test/release-changelog.test.js.map +0 -1
  825. package/dist/test/release-holds.test.d.ts +0 -2
  826. package/dist/test/release-holds.test.d.ts.map +0 -1
  827. package/dist/test/release-holds.test.js +0 -456
  828. package/dist/test/release-holds.test.js.map +0 -1
  829. package/dist/test/same-round-think-policy.test.d.ts +0 -2
  830. package/dist/test/same-round-think-policy.test.d.ts.map +0 -1
  831. package/dist/test/same-round-think-policy.test.js +0 -853
  832. package/dist/test/same-round-think-policy.test.js.map +0 -1
  833. package/dist/test/save-recent-image.test.d.ts +0 -26
  834. package/dist/test/save-recent-image.test.d.ts.map +0 -1
  835. package/dist/test/save-recent-image.test.js +0 -974
  836. package/dist/test/save-recent-image.test.js.map +0 -1
  837. package/dist/test/shutdown-errors.test.d.ts +0 -2
  838. package/dist/test/shutdown-errors.test.d.ts.map +0 -1
  839. package/dist/test/shutdown-errors.test.js +0 -662
  840. package/dist/test/shutdown-errors.test.js.map +0 -1
  841. package/dist/test/silent-heartbeat-rows.test.d.ts +0 -2
  842. package/dist/test/silent-heartbeat-rows.test.d.ts.map +0 -1
  843. package/dist/test/silent-heartbeat-rows.test.js +0 -451
  844. package/dist/test/silent-heartbeat-rows.test.js.map +0 -1
  845. package/dist/test/silent-heartbeat.test.d.ts +0 -2
  846. package/dist/test/silent-heartbeat.test.d.ts.map +0 -1
  847. package/dist/test/silent-heartbeat.test.js +0 -165
  848. package/dist/test/silent-heartbeat.test.js.map +0 -1
  849. package/dist/test/state-scaling-e2e.test.d.ts +0 -22
  850. package/dist/test/state-scaling-e2e.test.d.ts.map +0 -1
  851. package/dist/test/state-scaling-e2e.test.js +0 -206
  852. package/dist/test/state-scaling-e2e.test.js.map +0 -1
  853. package/dist/test/state-scaling.test.d.ts +0 -12
  854. package/dist/test/state-scaling.test.d.ts.map +0 -1
  855. package/dist/test/state-scaling.test.js +0 -251
  856. package/dist/test/state-scaling.test.js.map +0 -1
  857. package/dist/test/stop-with-host-operations.test.d.ts +0 -20
  858. package/dist/test/stop-with-host-operations.test.d.ts.map +0 -1
  859. package/dist/test/stop-with-host-operations.test.js +0 -1174
  860. package/dist/test/stop-with-host-operations.test.js.map +0 -1
  861. package/dist/test/stop-with-work-in-flight.test.d.ts +0 -23
  862. package/dist/test/stop-with-work-in-flight.test.d.ts.map +0 -1
  863. package/dist/test/stop-with-work-in-flight.test.js +0 -784
  864. package/dist/test/stop-with-work-in-flight.test.js.map +0 -1
  865. package/dist/test/surgery-marks-receipt.test.d.ts +0 -2
  866. package/dist/test/surgery-marks-receipt.test.d.ts.map +0 -1
  867. package/dist/test/surgery-marks-receipt.test.js +0 -540
  868. package/dist/test/surgery-marks-receipt.test.js.map +0 -1
  869. package/dist/test/thinking-token-stamp.test.d.ts +0 -12
  870. package/dist/test/thinking-token-stamp.test.d.ts.map +0 -1
  871. package/dist/test/thinking-token-stamp.test.js +0 -129
  872. package/dist/test/thinking-token-stamp.test.js.map +0 -1
  873. package/dist/test/timezone.test.d.ts +0 -2
  874. package/dist/test/timezone.test.d.ts.map +0 -1
  875. package/dist/test/timezone.test.js +0 -18
  876. package/dist/test/timezone.test.js.map +0 -1
  877. package/dist/test/tool-batch-hook.test.d.ts +0 -8
  878. package/dist/test/tool-batch-hook.test.d.ts.map +0 -1
  879. package/dist/test/tool-batch-hook.test.js +0 -275
  880. package/dist/test/tool-batch-hook.test.js.map +0 -1
  881. package/dist/test/tool-policy.test.d.ts +0 -2
  882. package/dist/test/tool-policy.test.d.ts.map +0 -1
  883. package/dist/test/tool-policy.test.js +0 -51
  884. package/dist/test/tool-policy.test.js.map +0 -1
  885. package/dist/test/tool-presentation.test.d.ts +0 -2
  886. package/dist/test/tool-presentation.test.d.ts.map +0 -1
  887. package/dist/test/tool-presentation.test.js +0 -268
  888. package/dist/test/tool-presentation.test.js.map +0 -1
  889. package/dist/test/tool-result-content.test.d.ts +0 -2
  890. package/dist/test/tool-result-content.test.d.ts.map +0 -1
  891. package/dist/test/tool-result-content.test.js +0 -37
  892. package/dist/test/tool-result-content.test.js.map +0 -1
  893. package/dist/test/tool-result-guard.test.d.ts +0 -2
  894. package/dist/test/tool-result-guard.test.d.ts.map +0 -1
  895. package/dist/test/tool-result-guard.test.js +0 -3729
  896. package/dist/test/tool-result-guard.test.js.map +0 -1
  897. package/dist/test/tool-result-history.test.d.ts +0 -7
  898. package/dist/test/tool-result-history.test.d.ts.map +0 -1
  899. package/dist/test/tool-result-history.test.js +0 -156
  900. package/dist/test/tool-result-history.test.js.map +0 -1
  901. package/dist/test/tool-result-spill.test.d.ts +0 -13
  902. package/dist/test/tool-result-spill.test.d.ts.map +0 -1
  903. package/dist/test/tool-result-spill.test.js +0 -586
  904. package/dist/test/tool-result-spill.test.js.map +0 -1
  905. package/dist/test/tool-wrapper-prose-guard-integration.test.d.ts +0 -2
  906. package/dist/test/tool-wrapper-prose-guard-integration.test.d.ts.map +0 -1
  907. package/dist/test/tool-wrapper-prose-guard-integration.test.js +0 -485
  908. package/dist/test/tool-wrapper-prose-guard-integration.test.js.map +0 -1
  909. package/dist/test/tool-wrapper-prose-guard.test.d.ts +0 -2
  910. package/dist/test/tool-wrapper-prose-guard.test.d.ts.map +0 -1
  911. package/dist/test/tool-wrapper-prose-guard.test.js +0 -34
  912. package/dist/test/tool-wrapper-prose-guard.test.js.map +0 -1
  913. package/dist/test/tools-observe-parser-conformance.test.d.ts +0 -2
  914. package/dist/test/tools-observe-parser-conformance.test.d.ts.map +0 -1
  915. package/dist/test/tools-observe-parser-conformance.test.js +0 -129
  916. package/dist/test/tools-observe-parser-conformance.test.js.map +0 -1
  917. package/dist/test/trunk-channel-routing.test.d.ts +0 -19
  918. package/dist/test/trunk-channel-routing.test.d.ts.map +0 -1
  919. package/dist/test/trunk-channel-routing.test.js +0 -652
  920. package/dist/test/trunk-channel-routing.test.js.map +0 -1
  921. package/dist/test/tune-out-e2e.test.d.ts +0 -2
  922. package/dist/test/tune-out-e2e.test.d.ts.map +0 -1
  923. package/dist/test/tune-out-e2e.test.js +0 -142
  924. package/dist/test/tune-out-e2e.test.js.map +0 -1
  925. package/dist/test/tune-out-gate-composition.test.d.ts +0 -2
  926. package/dist/test/tune-out-gate-composition.test.d.ts.map +0 -1
  927. package/dist/test/tune-out-gate-composition.test.js +0 -221
  928. package/dist/test/tune-out-gate-composition.test.js.map +0 -1
  929. package/dist/test/tune-out-lifecycle.test.d.ts +0 -2
  930. package/dist/test/tune-out-lifecycle.test.d.ts.map +0 -1
  931. package/dist/test/tune-out-lifecycle.test.js +0 -121
  932. package/dist/test/tune-out-lifecycle.test.js.map +0 -1
  933. package/dist/test/turn-trigger-provenance.test.d.ts +0 -2
  934. package/dist/test/turn-trigger-provenance.test.d.ts.map +0 -1
  935. package/dist/test/turn-trigger-provenance.test.js +0 -137
  936. package/dist/test/turn-trigger-provenance.test.js.map +0 -1
  937. package/dist/test/unconvertible-tool-result.test.d.ts +0 -2
  938. package/dist/test/unconvertible-tool-result.test.d.ts.map +0 -1
  939. package/dist/test/unconvertible-tool-result.test.js +0 -358
  940. package/dist/test/unconvertible-tool-result.test.js.map +0 -1
  941. package/dist/test/unsent-compiles.test.d.ts +0 -2
  942. package/dist/test/unsent-compiles.test.d.ts.map +0 -1
  943. package/dist/test/unsent-compiles.test.js +0 -139
  944. package/dist/test/unsent-compiles.test.js.map +0 -1
  945. package/dist/test/usage-accounting.test.d.ts +0 -2
  946. package/dist/test/usage-accounting.test.d.ts.map +0 -1
  947. package/dist/test/usage-accounting.test.js +0 -13
  948. package/dist/test/usage-accounting.test.js.map +0 -1
  949. package/dist/test/usage-tracker.test.d.ts +0 -2
  950. package/dist/test/usage-tracker.test.d.ts.map +0 -1
  951. package/dist/test/usage-tracker.test.js +0 -129
  952. package/dist/test/usage-tracker.test.js.map +0 -1
  953. package/dist/test/utils-surface.test.d.ts +0 -2
  954. package/dist/test/utils-surface.test.d.ts.map +0 -1
  955. package/dist/test/utils-surface.test.js +0 -145
  956. package/dist/test/utils-surface.test.js.map +0 -1
  957. package/dist/test/workspace-branch-continuation.test.d.ts +0 -15
  958. package/dist/test/workspace-branch-continuation.test.d.ts.map +0 -1
  959. package/dist/test/workspace-branch-continuation.test.js +0 -183
  960. package/dist/test/workspace-branch-continuation.test.js.map +0 -1
  961. package/dist/test/workspace-materialize-freshness.test.d.ts +0 -16
  962. package/dist/test/workspace-materialize-freshness.test.d.ts.map +0 -1
  963. package/dist/test/workspace-materialize-freshness.test.js +0 -252
  964. package/dist/test/workspace-materialize-freshness.test.js.map +0 -1
  965. package/dist/test/workspace-path-containment.test.d.ts +0 -19
  966. package/dist/test/workspace-path-containment.test.d.ts.map +0 -1
  967. package/dist/test/workspace-path-containment.test.js +0 -91
  968. package/dist/test/workspace-path-containment.test.js.map +0 -1
  969. package/dist/test/workspace-read-file-from-disk.test.d.ts +0 -17
  970. package/dist/test/workspace-read-file-from-disk.test.d.ts.map +0 -1
  971. package/dist/test/workspace-read-file-from-disk.test.js +0 -174
  972. package/dist/test/workspace-read-file-from-disk.test.js.map +0 -1
  973. package/dist/test/workspace-read-image.test.d.ts +0 -2
  974. package/dist/test/workspace-read-image.test.d.ts.map +0 -1
  975. package/dist/test/workspace-read-image.test.js +0 -597
  976. package/dist/test/workspace-read-image.test.js.map +0 -1
  977. package/dist/test/workspace-read-text.test.d.ts +0 -2
  978. package/dist/test/workspace-read-text.test.d.ts.map +0 -1
  979. package/dist/test/workspace-read-text.test.js +0 -101
  980. package/dist/test/workspace-read-text.test.js.map +0 -1
  981. package/dist/test/workspace-restore-order.test.d.ts +0 -16
  982. package/dist/test/workspace-restore-order.test.d.ts.map +0 -1
  983. package/dist/test/workspace-restore-order.test.js +0 -140
  984. package/dist/test/workspace-restore-order.test.js.map +0 -1
  985. package/dist/test/workspace-three-way.test.d.ts +0 -12
  986. package/dist/test/workspace-three-way.test.d.ts.map +0 -1
  987. package/dist/test/workspace-three-way.test.js +0 -4094
  988. package/dist/test/workspace-three-way.test.js.map +0 -1
  989. package/dist/test/workspace-watcher.test.d.ts +0 -2
  990. package/dist/test/workspace-watcher.test.d.ts.map +0 -1
  991. package/dist/test/workspace-watcher.test.js +0 -281
  992. package/dist/test/workspace-watcher.test.js.map +0 -1
  993. package/dist/test/xml-round-persist.test.d.ts +0 -19
  994. package/dist/test/xml-round-persist.test.d.ts.map +0 -1
  995. package/dist/test/xml-round-persist.test.js +0 -235
  996. package/dist/test/xml-round-persist.test.js.map +0 -1
  997. package/dist/tsconfig.tsbuildinfo +0 -1
@@ -0,0 +1,1182 @@
1
+ /**
2
+ * ModernMcpConnection: a server that speaks modern MCP (2026-07-28), reached
3
+ * over stdio or Streamable HTTP through the official SDK client.
4
+ *
5
+ * Responsibilities divide like this. The SDK owns the modern wire:
6
+ * `server/discover`, the per-request `_meta` envelope, `resultType`,
7
+ * continuation of `input_required` results, cancellation, list-change
8
+ * subscriptions, and the HTTP binding's headers, auth retry and
9
+ * header-mismatch handling. This class owns what Connectome decides:
10
+ * - **stdio** runs through Connectome's own spawner, so the child gets the
11
+ * same env allowlist, `inheritEnv` and stderr surfacing as a legacy server,
12
+ * and it starts once per connect. The SDK's own stdio transport starts a
13
+ * throwaway second copy for discovery.
14
+ * - **HTTP credentials** come from `token`/`accessProvider`: a cached bearer
15
+ * token, re-resolved once when the server answers 401.
16
+ * - **One deadline per tool call** (`requestTimeoutMs`, always positive)
17
+ * bounds every leg of the call and the pauses between them. At the
18
+ * deadline the SDK requests cancellation of a leg in flight; between
19
+ * continuation rounds nothing is in flight. Either way the outcome is
20
+ * unknown. Calls are never replayed. The protocol has no cancel for a
21
+ * call paused at `input_required`, so whatever the server holds for it,
22
+ * beyond the `requestState` it gave this client, stays until the server
23
+ * lets it go.
24
+ * - **Request outcomes from the wire.** A failed call is classified by what
25
+ * crossed Connectome's transport boundary, never by the error's class. The
26
+ * SDK raises the same error classes locally (an invalid outputSchema before
27
+ * dispatch, output validation after a successful result) as it does for
28
+ * server answers. A call's answer is the server's final one: an
29
+ * `input_required` answer asks for another round, so a call that ends
30
+ * after one has no answer.
31
+ * - **Lifetime.** On a lost transport the connection restarts with the same
32
+ * backoff settings as legacy, when `reconnect` is set, once the lost
33
+ * launch is reaped, so a second child never runs beside the first. A
34
+ * stdio child that stays alive but silently stops reading its stdin is
35
+ * no loss the pipes show: each call's deadline is the only bound on it.
36
+ * A server that shares no revision with this client is a configuration
37
+ * verdict, as for legacy (`McplProtocolVersionError`): it is never
38
+ * retried. List-change
39
+ * awareness is kept while the connection lives: a subscription the server
40
+ * advertises but that didn't open, or that ended, is reopened. Each connect
41
+ * is a generation, so a superseded client never touches a newer one.
42
+ * `close()` owns a connect in flight too.
43
+ *
44
+ * Nothing here is MCPL: a modern server has no grant, no planes and no
45
+ * server→host requests. The framework uses this connection only through its
46
+ * tool paths, and the MCPL machinery never sees it.
47
+ */
48
+ import { AsyncLocalStorage } from 'node:async_hooks';
49
+ import { EventEmitter } from 'node:events';
50
+
51
+ import {
52
+ Client,
53
+ InsufficientScopeError,
54
+ SdkError,
55
+ SdkErrorCode,
56
+ SdkHttpError,
57
+ StreamableHTTPClientTransport,
58
+ UnsupportedProtocolVersionError,
59
+ parseJSONRPCMessage,
60
+ type AuthProvider,
61
+ type CallToolResult,
62
+ type JSONRPCMessage,
63
+ type McpSubscription,
64
+ type MessageExtraInfo,
65
+ type Transport,
66
+ type TransportSendOptions,
67
+ } from '@modelcontextprotocol/client';
68
+
69
+ import { StdioTransport, type McplTransport } from './transport.js';
70
+ import { McplProtocolVersionError, McplRequestError, McplUnreapedLaunchError } from './server-connection.js';
71
+ import { LEGACY_MCP_PROTOCOL_VERSION, MAX_TIMER_MS, MODERN_MCP_PROTOCOL_VERSION, checkServerConfig, describeCredentialError, noteDialSent, redactServerText, serverTextRedactor } from './protocol-family.js';
72
+ import type { McplServerConfig, McpToolDefinition } from './types.js';
73
+ import { boundedForLog } from './errors.js';
74
+ import { logDetail, logValue, logValueRedacted } from './log-value.js';
75
+
76
+ const DEFAULT_REQUEST_TIMEOUT_MS = 60_000;
77
+ /** Bound on establishing the connection (`server/discover`), like the legacy
78
+ * engine's initialize timeout. */
79
+ const CONNECT_TIMEOUT_MS = 30_000;
80
+ /** Inventory listing has its own bound: it is host work, not a resident's call. */
81
+ const LIST_TIMEOUT_MS = 30_000;
82
+ /** Startup stderr kept for the first listener. */
83
+ const STDERR_BACKLOG_LINES = 200;
84
+
85
+ /** A modern tool result as the framework consumes it. `structuredContent` is
86
+ * kept by presence: `false`, `0` and `null` are values, not absence. */
87
+ export interface ModernToolCallResult {
88
+ content: CallToolResult['content'];
89
+ isError?: boolean;
90
+ structuredContent?: unknown;
91
+ _meta?: Record<string, unknown>;
92
+ }
93
+
94
+ /**
95
+ * What crossed Connectome's transport boundary for one logical request: were
96
+ * any of its requests handed to the transport, and how did the server answer
97
+ * the most recent one? A logical call can take several legs: a
98
+ * header-mismatch retry, or the rounds of an `input_required` continuation.
99
+ * Only an error or a `complete` result is the server's final answer.
100
+ * `input-required` asks for another round, and a result of any other type,
101
+ * or of none (`unrecognized`), doesn't say the call finished.
102
+ */
103
+ interface WireRecord {
104
+ readonly method: string;
105
+ handedOff: boolean;
106
+ currentId?: string | number;
107
+ /** The current leg's answer. */
108
+ answer: 'none' | 'error' | 'complete' | 'input-required' | 'unrecognized';
109
+ error?: { code: number; message: string; data?: unknown };
110
+ /** An earlier leg's answer asked for another round (or wasn't a complete
111
+ * result): the server may have acted on the call, whatever a later leg
112
+ * meets. A new leg's send never clears it. */
113
+ continued: boolean;
114
+ }
115
+
116
+ /**
117
+ * A send that Connectome's own transport refused before writing anything (its
118
+ * stdio line is closed): nothing of that request reached the server. `pipe`:
119
+ * the child's stdin or stdout had failed, so this host can no longer write to
120
+ * that server at all.
121
+ */
122
+ class NotWrittenError extends Error {
123
+ readonly pipe: boolean;
124
+ constructor(message: string, pipe = false) {
125
+ super(message);
126
+ this.name = 'NotWrittenError';
127
+ this.pipe = pipe;
128
+ }
129
+ }
130
+
131
+ /** The logical request a send belongs to. The SDK hands each request to the
132
+ * transport inside the caller's async chain, so the scope reaches `send`. */
133
+ const wireScope = new AsyncLocalStorage<WireRecord>();
134
+
135
+ /**
136
+ * The boundary between the SDK and the actual transport. It records, for the
137
+ * logical request in scope, each request of the observed method that it
138
+ * hands on, and the answer that comes back for it. Everything else passes
139
+ * through untouched: the SDK sees the inner transport's own members.
140
+ */
141
+ class ObservedTransport implements Transport {
142
+ onclose?: () => void;
143
+ onerror?: (error: Error) => void;
144
+ onmessage?: <T extends JSONRPCMessage>(message: T, extra?: MessageExtraInfo) => void;
145
+ private readonly awaiting = new Map<string | number, WireRecord>();
146
+
147
+ constructor(private readonly inner: Transport) {}
148
+
149
+ get sessionId(): string | undefined {
150
+ return this.inner.sessionId;
151
+ }
152
+
153
+ get hasPerRequestStream(): boolean | undefined {
154
+ return this.inner.hasPerRequestStream;
155
+ }
156
+
157
+ setProtocolVersion(version: string): void {
158
+ this.inner.setProtocolVersion?.(version);
159
+ }
160
+
161
+ setSupportedProtocolVersions(versions: string[]): void {
162
+ this.inner.setSupportedProtocolVersions?.(versions);
163
+ }
164
+
165
+ async start(): Promise<void> {
166
+ this.inner.onmessage = (message, extra) => {
167
+ // An answer to a request in scope is handed to the SDK inside that
168
+ // request's scope. The SDK drives an input_required continuation from
169
+ // this very callback, outside the caller's async chain, and the next
170
+ // leg's send must still be recorded against the right call.
171
+ const record = this.observe(message);
172
+ if (record) wireScope.run(record, () => this.onmessage?.(message, extra));
173
+ else this.onmessage?.(message, extra);
174
+ };
175
+ this.inner.onerror = (error) => this.onerror?.(error);
176
+ this.inner.onclose = () => this.onclose?.();
177
+ await this.inner.start();
178
+ }
179
+
180
+ async send(message: JSONRPCMessage, options?: TransportSendOptions): Promise<void> {
181
+ const record = wireScope.getStore();
182
+ let undo: (() => void) | undefined;
183
+ if (record && 'method' in message && 'id' in message && message.method === record.method) {
184
+ const prior = { handedOff: record.handedOff, currentId: record.currentId, answer: record.answer, error: record.error };
185
+ // Handed off from here on: past this point nothing proves it unsent,
186
+ // unless the transport says it wrote nothing.
187
+ record.handedOff = true;
188
+ record.currentId = message.id;
189
+ record.answer = 'none';
190
+ record.error = undefined;
191
+ this.awaiting.set(message.id, record);
192
+ undo = () => {
193
+ this.awaiting.delete(message.id);
194
+ Object.assign(record, prior);
195
+ };
196
+ }
197
+ try {
198
+ await this.inner.send(message, options);
199
+ } catch (error) {
200
+ // Refused before any write: this leg never reached the server, so the
201
+ // record is as it was before it. Any other throw (an HTTP send can fail
202
+ // after part of the request went out) leaves it handed off.
203
+ if (error instanceof NotWrittenError) undo?.();
204
+ throw error;
205
+ }
206
+ }
207
+
208
+ async close(): Promise<void> {
209
+ await this.inner.close();
210
+ }
211
+
212
+ /** Drop a finished request's entries (unanswered legs included). */
213
+ forget(record: WireRecord): void {
214
+ for (const [id, entry] of this.awaiting) if (entry === record) this.awaiting.delete(id);
215
+ }
216
+
217
+ /** Record an answer to a request in scope; returns its record when it
218
+ * answers that record's current leg. */
219
+ private observe(message: JSONRPCMessage): WireRecord | undefined {
220
+ if (typeof message !== 'object' || message === null) return undefined;
221
+ if (!('id' in message) || (!('result' in message) && !('error' in message))) return undefined;
222
+ const record = this.awaiting.get(message.id as string | number);
223
+ if (!record) return undefined;
224
+ this.awaiting.delete(message.id as string | number);
225
+ // A superseded leg's late answer says nothing about the current one.
226
+ if (record.currentId !== message.id) return undefined;
227
+ if ('error' in message) {
228
+ record.answer = 'error';
229
+ record.error = message.error as WireRecord['error'];
230
+ } else {
231
+ const result = (message as { result?: unknown }).result;
232
+ const type = typeof result === 'object' && result !== null ? (result as { resultType?: unknown }).resultType : undefined;
233
+ record.answer = type === 'complete' ? 'complete' : type === 'input_required' ? 'input-required' : 'unrecognized';
234
+ if (record.answer !== 'complete') record.continued = true;
235
+ }
236
+ return record;
237
+ }
238
+ }
239
+
240
+ /**
241
+ * The diagnostic for a line that is JSON but not a JSON-RPC message: the
242
+ * line's first 200 characters, after the configuration's credentials are
243
+ * replaced, so a credential across the cut can't leave its first part.
244
+ */
245
+ export function malformedLineDiagnostic(
246
+ config: McplServerConfig,
247
+ text: string,
248
+ error: unknown,
249
+ recorded: (text: unknown) => string = serverTextRedactor(config),
250
+ ): string {
251
+ // The parser's message can quote the line, so it's redacted too.
252
+ const shown = recorded(text);
253
+ const why = recorded(error instanceof Error ? error.message.split('\n')[0] : error);
254
+ return `MCP server "${config.id}" sent a malformed JSON-RPC message (${shown.length > 200 ? `${shown.slice(0, 200)}…` : shown}): ${why}`;
255
+ }
256
+
257
+ /**
258
+ * SDK `Transport` over Connectome's stdio spawner. Framing is the same
259
+ * newline-delimited JSON-RPC as legacy. Lines that are not JSON are ignored,
260
+ * as the legacy engine ignores them. Because this is a custom transport, the
261
+ * SDK runs `server/discover` on this very process instead of starting a
262
+ * throwaway copy, and cancels with `notifications/cancelled`, which is the
263
+ * stdio binding's mechanism.
264
+ */
265
+ class SpawnerStdioTransport implements Transport {
266
+ onclose?: () => void;
267
+ onerror?: (error: Error) => void;
268
+ onmessage?: <T extends JSONRPCMessage>(message: T, extra?: MessageExtraInfo) => void;
269
+ private line: McplTransport | null = null;
270
+ /** The spawn start() awaits, so a close() made meanwhile closes its child. */
271
+ private spawning: Promise<McplTransport> | null = null;
272
+
273
+ /** Built once for the transport: every malformed line uses it. */
274
+ private readonly recorded: (text: unknown) => string;
275
+
276
+ constructor(
277
+ private readonly config: McplServerConfig,
278
+ private readonly onStderr: (line: string) => void,
279
+ /** The child's pipe failed and it outlived SIGKILL too, so the line
280
+ * stays open, owning it (the line's 'unreaped'): `reason` names the
281
+ * pipe's error. */
282
+ private readonly onUnreaped: (reason: string) => void,
283
+ ) {
284
+ this.recorded = serverTextRedactor(config);
285
+ }
286
+
287
+ async start(): Promise<void> {
288
+ // A command that can't be spawned rejects here, with its spawn error, so
289
+ // the connect fails with it rather than waiting out its discover probe.
290
+ this.spawning = StdioTransport.spawn(this.config);
291
+ const line = await this.spawning;
292
+ this.line = line;
293
+ line.on('line', (text: string) => {
294
+ // A line that isn't JSON is ignored, as the legacy engine ignores it.
295
+ // A line that is JSON but not a JSON-RPC message (`null`, an array, a
296
+ // bare value) is a diagnostic. It must never reach a handler that
297
+ // assumes the shape: thrown from this callback, it would end the host.
298
+ let parsed: unknown;
299
+ try {
300
+ parsed = JSON.parse(text);
301
+ } catch {
302
+ return;
303
+ }
304
+ let message: JSONRPCMessage;
305
+ try {
306
+ message = parseJSONRPCMessage(parsed);
307
+ } catch (error) {
308
+ this.onerror?.(new Error(malformedLineDiagnostic(this.config, text, error, this.recorded)));
309
+ return;
310
+ }
311
+ this.onmessage?.(message);
312
+ });
313
+ line.on('stderr', (text: string) => this.onStderr(text));
314
+ line.on('error', (error: Error) => this.onerror?.(error));
315
+ line.on('close', () => this.onclose?.());
316
+ line.on('unreaped', () => this.onUnreaped(`its stdio pipe failed with ${line.pipeFailure?.message ?? 'an error'}`));
317
+ }
318
+
319
+ async send(message: JSONRPCMessage): Promise<void> {
320
+ if (!this.line || this.line.closed) throw new NotWrittenError(`MCP server "${this.config.id}" stdio transport is closed`);
321
+ // Once the child's stdin or stdout has failed, the line is ending it and
322
+ // writes nothing more to it, so a message is refused here as not sent.
323
+ const failed = this.line.pipeFailure;
324
+ if (failed) throw new NotWrittenError(`MCP server "${this.config.id}" stdio pipe failed with ${failed.message}`, true);
325
+ this.line.writeLine(JSON.stringify(message));
326
+ }
327
+
328
+ async close(): Promise<void> {
329
+ // A close() during the spawn closes the child it yields. start()
330
+ // awaited the spawn first, so the line is wired by then, and its close
331
+ // ends what the SDK has in flight, as it does after the spawn.
332
+ if (!this.line && this.spawning) await this.spawning.catch(() => null);
333
+ await this.line?.close();
334
+ }
335
+ }
336
+
337
+ /** Connectome's credential plumbing as the SDK's minimal bearer seam: a
338
+ * cached token, fetched on first use and once again after a 401. */
339
+ function bearerAuth(config: McplServerConfig): AuthProvider | undefined {
340
+ const provider = config.accessProvider;
341
+ if (!provider && !config.token) return undefined;
342
+ let cached: string | undefined;
343
+ const resolve = async (): Promise<string | undefined> => {
344
+ if (provider) {
345
+ try {
346
+ const fresh = await provider();
347
+ if (fresh) {
348
+ // Sent in the Authorization header: the server's text is recorded
349
+ // with it replaced.
350
+ noteDialSent(config, { token: fresh });
351
+ return fresh;
352
+ }
353
+ } catch (error) {
354
+ // Same fallback as the WebSocket dial: use the static token, and let
355
+ // the server refuse a stale credential loudly. The provider's own
356
+ // text may quote the credential, so it isn't logged.
357
+ console.error(
358
+ `[mcp] server "${config.id}": access provider failed (${describeCredentialError(error)}) — using configured fallback`,
359
+ );
360
+ }
361
+ }
362
+ return config.token;
363
+ };
364
+ return {
365
+ token: async () => (cached ??= await resolve()),
366
+ onUnauthorized: async () => {
367
+ cached = await resolve();
368
+ },
369
+ };
370
+ }
371
+
372
+ /** One connect generation's client and the boundary it talks through. */
373
+ interface Session {
374
+ readonly generation: number;
375
+ readonly client: Client;
376
+ readonly wire: ObservedTransport;
377
+ /** Its transport has closed, whether or not the session was adopted yet. */
378
+ lost: boolean;
379
+ }
380
+
381
+ export class ModernMcpConnection extends EventEmitter {
382
+ readonly id: string;
383
+ readonly family = 'modern' as const;
384
+ readonly transportKind: 'stdio' | 'http';
385
+ /** The pinned revision, once a connect has established it; null before. */
386
+ protocolVersion: string | null = null;
387
+
388
+ private session: Session | null = null;
389
+ /** A connect in flight, owned so `close()` can end it. */
390
+ private opening: { session: Session; done: Promise<void> } | null = null;
391
+ private generation = 0;
392
+ private closedByHost = false;
393
+ private reconnectEnabled: boolean;
394
+ private readonly reconnectIntervalMs: number;
395
+ private readonly reconnectMaxIntervalMs: number;
396
+ private reconnectTimer: ReturnType<typeof setTimeout> | null = null;
397
+ private reconnectAttempts = 0;
398
+ /** At most one pending reopen, and only ever for the current generation. */
399
+ private relisten: { generation: number; timer: ReturnType<typeof setTimeout> } | null = null;
400
+ private relistenAttempts = 0;
401
+ /**
402
+ * Generations whose cleanup could not confirm their child exited. While any
403
+ * is held, no replacement is started: launching another would orphan the
404
+ * first. close() retries them and reports what still fails.
405
+ */
406
+ private unreaped: Array<{ session: Session; failure: Error }> = [];
407
+ /** A lost session's reap in flight: the reconnect follows it, and
408
+ * close() waits for it. */
409
+ private losing: { session: Session; done: Promise<void> } | null = null;
410
+ /** Child stderr from before anyone listens (the caller attaches only once
411
+ * connect() returns), delivered to the first listener. Bounded: the
412
+ * newest lines are kept. */
413
+ private stderrBacklog: string[] = [];
414
+
415
+ private constructor(private readonly config: McplServerConfig) {
416
+ super();
417
+ this.id = config.id;
418
+ const binding = checkServerConfig(config);
419
+ if (binding.family !== 'modern') {
420
+ throw new Error(`MCP server "${config.id}" is not configured for modern MCP; it belongs to McplServerConnection`);
421
+ }
422
+ this.transportKind = binding.transport === 'http' ? 'http' : 'stdio';
423
+ this.reconnectEnabled = config.reconnect === true;
424
+ this.reconnectIntervalMs = config.reconnectIntervalMs ?? 5000;
425
+ this.reconnectMaxIntervalMs = config.reconnectMaxIntervalMs ?? 300_000;
426
+ // An 'error' with no listener would throw out of an SDK callback and take
427
+ // the host down; out-of-band errors here are diagnostics, never fatal.
428
+ this.on('error', (error: Error) => {
429
+ if (this.listenerCount('error') === 1) console.error(`[mcp] ${this.id}: ${redactServerText(error.message, this.config)}`);
430
+ });
431
+ this.on('newListener', (event: string | symbol) => {
432
+ if (event !== 'stderr' || this.stderrBacklog.length === 0) return;
433
+ const pending = this.stderrBacklog;
434
+ this.stderrBacklog = [];
435
+ // After the listener is added (newListener fires just before).
436
+ queueMicrotask(() => { for (const line of pending) this.emit('stderr', { line }); });
437
+ });
438
+ }
439
+
440
+ private deliverStderr(line: string): void {
441
+ if (this.listenerCount('stderr') > 0) {
442
+ this.emit('stderr', { line });
443
+ return;
444
+ }
445
+ this.stderrBacklog.push(line);
446
+ if (this.stderrBacklog.length > STDERR_BACKLOG_LINES) this.stderrBacklog.shift();
447
+ }
448
+
449
+ /** The per-call deadline: `requestTimeoutMs`, validated positive. */
450
+ get requestTimeoutMs(): number {
451
+ return this.config.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
452
+ }
453
+
454
+ get isConnected(): boolean {
455
+ return this.session !== null;
456
+ }
457
+
458
+ /** Whether a lost connection will be re-established in the background. */
459
+ get willReconnect(): boolean {
460
+ return this.reconnectEnabled && !this.closedByHost && this.unreaped.length === 0;
461
+ }
462
+
463
+ /** Whether close() has been called: closed for good, or closing. A
464
+ * connection lost on its own is not closed in this sense. */
465
+ get isClosed(): boolean {
466
+ return this.closedByHost;
467
+ }
468
+
469
+ /** Whether a child this connection launched couldn't be confirmed exited.
470
+ * While it's true the connection owns that child, so whatever registered
471
+ * it keeps its id held; close() retries the reap. It's settled only once
472
+ * a reap has finished: while a lost session's reap or a close runs, it
473
+ * reads false, so read it once lossReaped() or close() has settled. */
474
+ get holdsUnreapedChild(): boolean {
475
+ return this.unreaped.length > 0;
476
+ }
477
+
478
+ /** The reap of a session lost on its own, settled once it's done, whether
479
+ * or not it confirmed the child exited (holdsUnreapedChild says which);
480
+ * settled at once when no such reap is running. */
481
+ lossReaped(): Promise<void> {
482
+ return this.losing?.done ?? Promise.resolve();
483
+ }
484
+
485
+ /** A failed generation's cleanup couldn't reap its child: keep owning it,
486
+ * and halt reconnecting until close() settles it. */
487
+ private holdUnreaped(session: Session, failure: Error): void {
488
+ if (this.unreaped.some((held) => held.session === session)) return;
489
+ this.unreaped.push({ session, failure });
490
+ this.emit('error', new Error(
491
+ `MCP server "${this.id}": ${failure.message}. Not starting another launch while it may still be running; close the connection to retry the reap.`,
492
+ ));
493
+ }
494
+
495
+ /** The halt, as a permanent failure for the reconnect events. */
496
+ private unreapedFailure(): string | null {
497
+ const held = this.unreaped[0];
498
+ if (!held) return null;
499
+ const halted = this.reconnectEnabled ? '; reconnecting is halted' : '';
500
+ return `the previous launch could not be reaped (${held.failure.message})${halted}`;
501
+ }
502
+
503
+ /**
504
+ * A connection that hasn't started: configuration is validated (and
505
+ * throws), nothing is launched or dialed. An owner can register it, and
506
+ * wire its events, before {@link start}, so a connect in flight is
507
+ * already the owner's to close.
508
+ */
509
+ static create(config: McplServerConfig): ModernMcpConnection {
510
+ return new ModernMcpConnection(config);
511
+ }
512
+
513
+ /** The first connect, shared by every call to start(). */
514
+ private starting: Promise<void> | null = null;
515
+
516
+ /**
517
+ * The first connect. Without `reconnect` a failure throws. With it, the
518
+ * connection keeps retrying in the background, as the legacy engine's
519
+ * stub does, and reports `connect-failed`, unless the failed launch
520
+ * couldn't be reaped: no retry can come then, so it throws too. A
521
+ * connection closed before or during its first connect resolves
522
+ * unconnected. A connection starts once:
523
+ * later calls return the first call's promise, so a second session never
524
+ * opens beside the first.
525
+ */
526
+ start(): Promise<void> {
527
+ return (this.starting ??= this.firstConnect());
528
+ }
529
+
530
+ private async firstConnect(): Promise<void> {
531
+ try {
532
+ await this.open();
533
+ } catch (error) {
534
+ if (this.closedByHost) return;
535
+ // No common revision is a configuration fact, not an outage: a retry
536
+ // would restart the server to hear the same answer.
537
+ if (error instanceof McplProtocolVersionError) {
538
+ this.reconnectEnabled = false;
539
+ throw error;
540
+ }
541
+ // A launch that couldn't be reaped halts reconnecting, so no retry
542
+ // will come: the first connect fails, as one without reconnect does.
543
+ if (!this.reconnectEnabled || this.holdsUnreapedChild) throw error;
544
+ console.error(`MCP server "${this.id}" initial connect failed, will retry:`, redactServerText((error as Error).message, this.config));
545
+ this.reconnectAttempts = 1;
546
+ this.emit('connect-failed', { error: (error as Error).message, attempt: 0 });
547
+ this.scheduleReconnect();
548
+ }
549
+ }
550
+
551
+ /**
552
+ * {@link create} and {@link start} in one step. A first connect that fails
553
+ * and whose cleanup couldn't confirm its child exited throws
554
+ * {@link McplUnreapedLaunchError}, whose connection owns that launch, as
555
+ * the legacy engine's connect does: its close() retries the reap.
556
+ */
557
+ static async connect(config: McplServerConfig): Promise<ModernMcpConnection> {
558
+ const connection = ModernMcpConnection.create(config);
559
+ try {
560
+ await connection.start();
561
+ } catch (error) {
562
+ const held = connection.unreaped[0];
563
+ if (held) throw new McplUnreapedLaunchError(connection, error instanceof Error ? error : new Error(String(error)), held.failure);
564
+ throw error;
565
+ }
566
+ return connection;
567
+ }
568
+
569
+ private isCurrent(generation: number): boolean {
570
+ return generation === this.generation && !this.closedByHost;
571
+ }
572
+
573
+ /** One connect generation: a fresh client over a fresh transport. */
574
+ private async open(): Promise<void> {
575
+ // Closed before this connect began: launch nothing.
576
+ if (this.closedByHost) return;
577
+ const generation = ++this.generation;
578
+ this.cancelRelisten();
579
+ // A new generation's subscription has failed nothing yet: its first
580
+ // reopen backs off from the base interval, not from the previous
581
+ // generation's failures.
582
+ this.relistenAttempts = 0;
583
+ const inner: Transport = this.transportKind === 'stdio'
584
+ ? new SpawnerStdioTransport(
585
+ this.config,
586
+ (line) => { if (this.isCurrent(generation)) this.deliverStderr(line); },
587
+ // A child whose pipe failed and that outlived SIGKILL: a loss, whose
588
+ // reap finds the child still running and holds the launch, as for any
589
+ // launch it can't reap. During a connect there is no session to lose
590
+ // yet: the connect's own cleanup holds it, once the connect fails.
591
+ (reason) => { if (this.isCurrent(generation)) this.handleLost(generation, reason); },
592
+ )
593
+ : new StreamableHTTPClientTransport(new URL(this.config.url!), { authProvider: bearerAuth(this.config) });
594
+ const wire = new ObservedTransport(inner);
595
+
596
+ const client = new Client(
597
+ { name: 'agent-framework', version: '1.0.0' },
598
+ {
599
+ versionNegotiation: { mode: { pin: MODERN_MCP_PROTOCOL_VERSION } },
600
+ // Nothing advertised: this client supplies no sampling, elicitation
601
+ // or roots, so a conforming server cannot require them.
602
+ capabilities: {},
603
+ listChanged: {
604
+ tools: {
605
+ autoRefresh: false,
606
+ debounceMs: 0,
607
+ onChanged: () => { if (this.isCurrent(generation)) this.emit('tools-list-changed'); },
608
+ },
609
+ },
610
+ },
611
+ );
612
+ const session: Session = { generation, client, wire, lost: false };
613
+ client.onerror = (error: Error) => {
614
+ // The SDK reports late responses to deadline-abandoned calls here
615
+ // ("unknown message ID"), and a list-change subscription it could not
616
+ // open at connect, among other out-of-band errors. They are emitted as
617
+ // this connection's 'error', so they reach the host's error listeners
618
+ // (and are logged when there are none). They never change a call's
619
+ // outcome, which was already reported.
620
+ if (this.isCurrent(generation)) this.emit('error', error);
621
+ };
622
+ client.onclose = () => {
623
+ // Marked before the session is adopted too: a close during the connect
624
+ // makes it a failed connect (see establish).
625
+ session.lost = true;
626
+ if (this.isCurrent(generation)) this.handleLost(generation, 'transport closed');
627
+ };
628
+
629
+ // `done` settles only once this connect's own cleanup has finished, on
630
+ // every path: close() waits on it, and must not resolve while that
631
+ // cleanup could still find a child it can't reap.
632
+ let settle!: () => void;
633
+ this.opening = { session, done: new Promise<void>((resolve) => { settle = resolve; }) };
634
+ try {
635
+ await this.establish(session);
636
+ } finally {
637
+ if (this.opening?.session === session) this.opening = null;
638
+ settle();
639
+ }
640
+ }
641
+
642
+ /** Connect one generation's client, and adopt it if it's still current. */
643
+ private async establish(session: Session): Promise<void> {
644
+ try {
645
+ await session.client.connect(session.wire, { timeout: CONNECT_TIMEOUT_MS });
646
+ } catch (error) {
647
+ const failure = await ModernMcpConnection.closeSession(session);
648
+ if (failure) this.holdUnreaped(session, failure);
649
+ throw this.versionVerdict(error) ?? error;
650
+ }
651
+ if (!this.isCurrent(session.generation)) {
652
+ // Superseded or closed while connecting: this generation never serves.
653
+ const failure = await ModernMcpConnection.closeSession(session);
654
+ if (failure) this.holdUnreaped(session, failure);
655
+ return;
656
+ }
657
+ if (session.lost) {
658
+ // The transport closed while the client connected, such as a child
659
+ // that exited at the connect-time list-change subscribe: the SDK
660
+ // reports that subscribe's failure only as an error, and resolves the
661
+ // connect anyway (R1-2). Adopted, the session would read as connected
662
+ // with nothing behind it, and no later close would come to reconnect
663
+ // it. So the connect failed.
664
+ const failure = await ModernMcpConnection.closeSession(session);
665
+ if (failure) this.holdUnreaped(session, failure);
666
+ throw new Error(`MCP server "${this.id}" closed its connection while connecting`);
667
+ }
668
+ this.session = session;
669
+ this.protocolVersion = MODERN_MCP_PROTOCOL_VERSION;
670
+ this.reconnectAttempts = 0;
671
+ this.keepListening(session, session.client.autoOpenedSubscription);
672
+ }
673
+
674
+ /**
675
+ * The server refused the pinned revision (no common one in its
676
+ * `server/discover` answer, or an unsupported-version error): a
677
+ * configuration verdict, as for the legacy engine, in the same type, so
678
+ * every reader treats both engines alike. Retrying can't change it.
679
+ */
680
+ private versionVerdict(error: unknown): McplProtocolVersionError | null {
681
+ if (!(error instanceof UnsupportedProtocolVersionError)) return null;
682
+ const data = (error as { data?: unknown }).data as { supported?: unknown } | undefined;
683
+ const supported = Array.isArray(data?.supported) && data.supported.every((v) => typeof v === 'string')
684
+ ? (data.supported as string[])
685
+ : null;
686
+ // Legacy MCP is reached over stdio or WebSocket. A stdio server's
687
+ // family is its configuration's choice; an http(s) url is modern by its
688
+ // scheme, so there is nothing to reconfigure on it.
689
+ const legacyHint = !supported?.includes(LEGACY_MCP_PROTOCOL_VERSION)
690
+ ? ''
691
+ : this.transportKind === 'stdio'
692
+ ? ` It speaks legacy MCP: configure it without protocol: 'modern'.`
693
+ : ` It speaks only legacy MCP, which this client reaches over stdio or WebSocket (ws://, wss://), not http(s).`;
694
+ return new McplProtocolVersionError(
695
+ `MCP server "${this.id}" does not support MCP ${MODERN_MCP_PROTOCOL_VERSION}` +
696
+ (supported ? ` (it supports: ${supported.join(', ') || 'none listed'}).` : ` (${error.message}).`) +
697
+ legacyHint,
698
+ 'rejected',
699
+ null,
700
+ supported,
701
+ (error as { code?: unknown }).code === undefined ? undefined : Number((error as { code?: unknown }).code),
702
+ (error as { data?: unknown }).data,
703
+ MODERN_MCP_PROTOCOL_VERSION,
704
+ );
705
+ }
706
+
707
+ /**
708
+ * Keep list-change awareness while this generation lives. The SDK opens the
709
+ * subscription at connect when the server advertises tool list changes. If
710
+ * that open failed (the SDK reports it through `onerror` and connects
711
+ * anyway), or the subscription later ends without our asking, it is
712
+ * reopened with backoff. Once it's back the inventory is refreshed, since
713
+ * changes may have been missed. A lost transport is the reconnect path's
714
+ * job, not this one's.
715
+ */
716
+ private keepListening(session: Session, subscription: McpSubscription | undefined): void {
717
+ if (!session.client.getServerCapabilities()?.tools?.listChanged) return;
718
+ if (!subscription) {
719
+ this.scheduleRelisten(session.generation);
720
+ return;
721
+ }
722
+ void subscription.closed.then((reason) => {
723
+ if (reason === 'local' || this.session !== session || !this.isCurrent(session.generation)) return;
724
+ this.scheduleRelisten(session.generation);
725
+ });
726
+ }
727
+
728
+ private cancelRelisten(): void {
729
+ if (this.relisten) clearTimeout(this.relisten.timer);
730
+ this.relisten = null;
731
+ }
732
+
733
+ private scheduleRelisten(generation: number): void {
734
+ if (!this.isCurrent(generation)) return;
735
+ if (this.relisten?.generation === generation) return;
736
+ this.cancelRelisten();
737
+ const timer = setTimeout(() => {
738
+ if (this.relisten?.timer === timer) this.relisten = null;
739
+ void this.reopenSubscription(generation);
740
+ }, this.backoffDelay(Math.max(1, this.relistenAttempts)));
741
+ timer.unref?.();
742
+ this.relisten = { generation, timer };
743
+ }
744
+
745
+ private async reopenSubscription(generation: number): Promise<void> {
746
+ const session = this.session;
747
+ if (!session || session.generation !== generation || !this.isCurrent(generation)) return;
748
+ try {
749
+ const subscription = await session.client.listen({ toolsListChanged: true }, { timeout: CONNECT_TIMEOUT_MS });
750
+ if (this.session !== session || !this.isCurrent(generation)) {
751
+ await subscription.close().catch(() => {});
752
+ return;
753
+ }
754
+ this.relistenAttempts = 0;
755
+ this.keepListening(session, subscription);
756
+ this.emit('tools-list-changed');
757
+ } catch (error) {
758
+ if (this.session !== session || !this.isCurrent(generation)) return;
759
+ this.relistenAttempts++;
760
+ this.emit('error', new Error(`MCP server "${this.id}" could not reopen its list-change subscription: ${(error as Error).message}`));
761
+ this.scheduleRelisten(generation);
762
+ }
763
+ }
764
+
765
+ /** The transport went away (child exit, or a closed HTTP client). */
766
+ private handleLost(generation: number, reason: string): void {
767
+ const session = this.session;
768
+ if (session?.generation !== generation) return;
769
+ this.session = null;
770
+ this.cancelRelisten();
771
+ // Reap before any reconnect, so a second child never runs beside the
772
+ // first. A transport usually closes once its child has exited, but a
773
+ // loss read from a failed pipe can come while the child still runs
774
+ // (R1-1). A launch that can't be reaped halts reconnecting, as a failed
775
+ // reconnect's does, and is a permanent failure, as that one is: no
776
+ // later attempt will come. The reap starts, and is recorded, before
777
+ // 'close' is emitted, so a listener that throws can't skip it.
778
+ const done = ModernMcpConnection.closeSession(session).then((failure) => {
779
+ if (this.losing?.session === session) this.losing = null;
780
+ if (failure) {
781
+ this.holdUnreaped(session, failure);
782
+ // A close() the host made meanwhile reports the failure itself.
783
+ if (!this.closedByHost) {
784
+ this.emit('reconnect-failed', { error: `${reason}; ${this.unreapedFailure()}`, attempt: Math.max(1, this.reconnectAttempts), permanent: true });
785
+ }
786
+ } else if (this.willReconnect) this.scheduleReconnect();
787
+ });
788
+ this.losing = { session, done };
789
+ this.emit('close', { reason });
790
+ }
791
+
792
+ /** The legacy engine's backoff: doubling from the base interval, capped,
793
+ * with ±25% jitter, and never past the timer limit (a longer delay would
794
+ * fire at once, turning the backoff into a tight loop). */
795
+ private backoffDelay(failures: number): number {
796
+ const exponent = Math.max(0, Math.min(failures - 1, 30));
797
+ const capped = Math.min(this.reconnectIntervalMs * 2 ** exponent, this.reconnectMaxIntervalMs);
798
+ return Math.min(capped * (0.75 + Math.random() * 0.5), MAX_TIMER_MS);
799
+ }
800
+
801
+ private scheduleReconnect(): void {
802
+ if (!this.willReconnect || this.reconnectTimer) return;
803
+ this.reconnectTimer = setTimeout(() => {
804
+ this.reconnectTimer = null;
805
+ void this.attemptReconnect();
806
+ }, this.backoffDelay(this.reconnectAttempts));
807
+ }
808
+
809
+ private async attemptReconnect(): Promise<void> {
810
+ if (!this.willReconnect || this.session) return;
811
+ const attempt = Math.max(1, this.reconnectAttempts);
812
+ try {
813
+ await this.open();
814
+ if (!this.session) return;
815
+ console.error(`MCP server "${this.id}" reconnected`);
816
+ this.emit('reconnect', { attempts: attempt });
817
+ } catch (error) {
818
+ if (this.closedByHost) return;
819
+ this.reconnectAttempts = attempt + 1;
820
+ const halted = this.unreapedFailure();
821
+ if (halted) {
822
+ this.emit('reconnect-failed', { error: `${(error as Error).message}; ${halted}`, attempt, permanent: true });
823
+ return;
824
+ }
825
+ // No common revision: every further attempt would hear the same
826
+ // answer. Stop; only the configuration can fix it.
827
+ if (error instanceof McplProtocolVersionError) {
828
+ this.reconnectEnabled = false;
829
+ this.emit('reconnect-failed', { error: error.message, attempt, permanent: true });
830
+ return;
831
+ }
832
+ this.emit('reconnect-failed', { error: (error as Error).message, attempt });
833
+ this.scheduleReconnect();
834
+ }
835
+ }
836
+
837
+ /**
838
+ * The server's complete tool inventory. The SDK follows every page; one
839
+ * budget, {@link LIST_TIMEOUT_MS}, bounds the whole walk, not each page.
840
+ * Its failures use the request-outcome contract with `tools/list` as the
841
+ * observed method. A relist the SDK makes inside a tool call is auxiliary
842
+ * to that call, and leaves the call's evidence alone.
843
+ */
844
+ async listTools(): Promise<McpToolDefinition[]> {
845
+ const { tools } = await this.request('tools/list', 'tools/list', (client) =>
846
+ client.listTools(undefined, {
847
+ cacheMode: 'refresh',
848
+ timeout: LIST_TIMEOUT_MS,
849
+ signal: AbortSignal.timeout(LIST_TIMEOUT_MS),
850
+ }), LIST_TIMEOUT_MS);
851
+ return tools.map((tool) => ({
852
+ name: tool.name,
853
+ ...(tool.description !== undefined ? { description: tool.description } : {}),
854
+ inputSchema: tool.inputSchema as Record<string, unknown>,
855
+ ...(tool._meta !== undefined ? { _meta: tool._meta as Record<string, unknown> } : {}),
856
+ }));
857
+ }
858
+
859
+ /**
860
+ * Call a tool within the configured deadline. One budget covers the whole
861
+ * logical call: the SDK's per-leg timer and its `maxTotalTimeout` across
862
+ * continuation rounds, and an abort signal around any retry the SDK makes
863
+ * before dispatch (an auth refresh, or a header-mismatch relist).
864
+ */
865
+ async callTool(name: string, args: Record<string, unknown>): Promise<ModernToolCallResult> {
866
+ const timeoutMs = this.requestTimeoutMs;
867
+ const result = await this.request('tools/call', `tools/call ${logValue(name)}`, (client) =>
868
+ client.callTool(
869
+ { name, arguments: args },
870
+ { timeout: timeoutMs, maxTotalTimeout: timeoutMs, signal: AbortSignal.timeout(timeoutMs) },
871
+ ), timeoutMs);
872
+ return {
873
+ content: result.content ?? [],
874
+ ...(result.isError !== undefined ? { isError: result.isError } : {}),
875
+ ...('structuredContent' in result ? { structuredContent: result.structuredContent } : {}),
876
+ ...(result._meta !== undefined ? { _meta: result._meta as Record<string, unknown> } : {}),
877
+ };
878
+ }
879
+
880
+ /** Run one logical request in a wire scope, and classify its failure by
881
+ * what that scope saw. `what` names the request in the host's log: its
882
+ * method, and a tool call's tool as a log field. */
883
+ private async request<T>(method: string, what: string, run: (client: Client) => Promise<T>, timeoutMs?: number): Promise<T> {
884
+ const session = this.session;
885
+ if (!session) {
886
+ // Connectome refuses before anything reaches the SDK: provably not
887
+ // sent. In the agent's words, as the legacy engine's request on a
888
+ // closed connection: after this host's own close, only that holds;
889
+ // otherwise the connection is closed, and whether this host is
890
+ // reconnecting says what works from there.
891
+ throw new McplRequestError(
892
+ this.closedByHost
893
+ ? `The request wasn't sent: this host closed its connection to the "${this.id}" server, so nothing ran. ` +
894
+ 'If calling it again fails, ask whoever runs this host.'
895
+ : `The request wasn't sent: the connection to the "${this.id}" server is closed, so nothing ran. ${this.retryText()}`,
896
+ 'not-sent',
897
+ );
898
+ }
899
+ const record: WireRecord = { method, handedOff: false, answer: 'none', continued: false };
900
+ try {
901
+ return await wireScope.run(record, () => run(session.client));
902
+ } catch (error) {
903
+ throw this.requestFailure(what, record, error, timeoutMs, session.lost);
904
+ } finally {
905
+ session.wire.forget(record);
906
+ }
907
+ }
908
+
909
+ /**
910
+ * Close one generation: the transport first (during discovery the SDK
911
+ * hasn't attached it yet, so only closing it ends the probe), then the
912
+ * client. The transport's close is the reaping verdict, and its failure is
913
+ * returned, never swallowed. It never rejects, which lossReaped() and the
914
+ * framework's unguarded wait on it rely on.
915
+ */
916
+ private static async closeSession(session: Session): Promise<Error | null> {
917
+ let failure: Error | null = null;
918
+ try {
919
+ await session.wire.close();
920
+ } catch (error) {
921
+ failure = error instanceof Error ? error : new Error(String(error));
922
+ }
923
+ await session.client.close().catch(() => { /* SDK teardown; the verdict is the transport's */ });
924
+ return failure;
925
+ }
926
+
927
+ /** The close in flight, which later calls wait behind. */
928
+ private closing: Promise<void> | null = null;
929
+
930
+ /** Set when the host closes a live session; cleared, with the one
931
+ * 'close', by the close that confirms its teardown. */
932
+ private closeIncomplete = false;
933
+
934
+ /**
935
+ * Close for good: no reconnect, no reopened subscription, no connect left
936
+ * in flight. Awaits the in-flight connect's end, and rejects while a child
937
+ * can't be confirmed exited: with that failure itself, the transport's
938
+ * own error, or an AggregateError when there are several, as the MCPL
939
+ * engine does. Calls queue behind the one in flight, so none resolves
940
+ * while teardown is still pending. A call after a failed close re-checks
941
+ * what wasn't reaped. 'close' is emitted once, when the teardown of a
942
+ * session the host closed while live completes, not on a failed close.
943
+ */
944
+ close(): Promise<void> {
945
+ // Closed from this call on: a connect or start() in the same turn sees
946
+ // it, and launches nothing.
947
+ this.closedByHost = true;
948
+ const previous = this.closing;
949
+ const next = (previous ? previous.catch(() => {}) : Promise.resolve()).then(() => this.closeStep());
950
+ this.closing = next;
951
+ return next;
952
+ }
953
+
954
+ private async closeStep(): Promise<void> {
955
+ this.closedByHost = true;
956
+ if (this.reconnectTimer) clearTimeout(this.reconnectTimer);
957
+ this.reconnectTimer = null;
958
+ this.cancelRelisten();
959
+ const opening = this.opening;
960
+ const losing = this.losing;
961
+ const session = this.session;
962
+ this.session = null;
963
+ if (session) this.closeIncomplete = true;
964
+ // Every generation this connection still owns: a connect in flight, the
965
+ // live one, a lost one still being reaped, and any a failed cleanup
966
+ // couldn't reap.
967
+ const targets: Session[] = [];
968
+ if (opening) targets.push(opening.session);
969
+ if (session) targets.push(session);
970
+ if (losing) targets.push(losing.session);
971
+ for (const held of this.unreaped) if (!targets.includes(held.session)) targets.push(held.session);
972
+ this.unreaped = [];
973
+ const failures: Error[] = [];
974
+ for (const target of targets) {
975
+ // Closing the transport ends a probe in flight too: its connect then
976
+ // rejects and its own cleanup runs (sharing this verdict).
977
+ const failure = await ModernMcpConnection.closeSession(target);
978
+ if (failure) {
979
+ failures.push(failure);
980
+ if (!this.unreaped.some((held) => held.session === target)) this.unreaped.push({ session: target, failure });
981
+ }
982
+ }
983
+ // The connect's own cleanup, and a lost session's reap, close their
984
+ // generation again, after the close above; each `done` settles once it
985
+ // has. A child that either cleanup couldn't reap is this close's failure
986
+ // too.
987
+ for (const pending of [opening, losing]) {
988
+ if (!pending) continue;
989
+ await pending.done;
990
+ for (const held of this.unreaped) if (!failures.includes(held.failure)) failures.push(held.failure);
991
+ }
992
+ if (failures.length === 1) throw failures[0];
993
+ if (failures.length > 1) {
994
+ throw new AggregateError(failures, `MCP server "${this.id}" did not close cleanly: ${failures.map((f) => f.message).join('; ')}`);
995
+ }
996
+ if (this.closeIncomplete) {
997
+ this.closeIncomplete = false;
998
+ this.emit('close', { reason: 'closed by host' });
999
+ }
1000
+ }
1001
+
1002
+ /** What works from here after a request that didn't run, by whether this
1003
+ * host is reconnecting to the server, in the legacy engine's words. */
1004
+ private retryText(): string {
1005
+ return this.willReconnect
1006
+ ? 'This host is reconnecting to it; try again later.'
1007
+ : "This host won't reconnect to it on its own. If you need it, ask whoever runs this host.";
1008
+ }
1009
+
1010
+ /**
1011
+ * Map a failure onto the request-outcome contract by what crossed the
1012
+ * transport boundary for this request, claiming no more than that shows.
1013
+ * The rules apply in this order. The call's answer is the server's final
1014
+ * one: an error or a `complete` result.
1015
+ * - nothing handed to the transport: `not-sent`, whatever was raised (a
1016
+ * pre-dispatch validation, a signal already aborted, no transport, a send
1017
+ * Connectome's stdio line refused before writing, an HTTP refusal before
1018
+ * any request went out);
1019
+ * - the most recent leg answered with a JSON-RPC error: `error-response`
1020
+ * with that error's data;
1021
+ * - the most recent leg answered with a complete result: the server
1022
+ * finished, but what it returned can't be used (output validation).
1023
+ * That's a plain error, not a request outcome;
1024
+ * - the most recent leg answered without finishing the call: `no-response`,
1025
+ * since the server may have acted on what it received. An
1026
+ * `input_required` answer asks for another round, and the call can end
1027
+ * before that round is sent: at the deadline, when the connection is
1028
+ * gone, or when this client can't go on (input it can't supply, the
1029
+ * rounds cap). Nothing is in flight then, so nothing is cancelled. A
1030
+ * result of a type this client doesn't recognize ends the call where it
1031
+ * is;
1032
+ * - an HTTP 401/403 refusal of the current leg: `error-response`, the
1033
+ * status in `data.httpStatus` (the server answered at the HTTP layer,
1034
+ * outside the JSON-RPC code space). After an earlier leg
1035
+ * asked for another round it is `no-response` instead: the server may
1036
+ * already have acted on the call;
1037
+ * - handed off and unanswered: `no-response`. At the deadline, cancellation
1038
+ * was requested and the outcome is unknown.
1039
+ *
1040
+ * The message is the agent's, in the legacy engine's words where it has
1041
+ * words for the same outcome (#506), and in their shape where it hasn't:
1042
+ * what happened, whether anything took effect, and what works from there.
1043
+ * A request this host's close cut off, and one whose connection closed
1044
+ * under it (`lost`), read as the legacy engine's do. The method, the tool,
1045
+ * the JSON-RPC code, the HTTP status, the deadline in milliseconds and the
1046
+ * SDK's or transport's words are the operator's, so they go to one log
1047
+ * line, the server's text redacted. Where the effect is in doubt, a tool
1048
+ * call's message says to check it before trying again, and a listing's that
1049
+ * listing changes nothing on the server, so trying again is safe.
1050
+ */
1051
+ private requestFailure(what: string, record: WireRecord, error: unknown, timeoutMs?: number, lost = false): Error {
1052
+ const server = `the "${this.id}" server`;
1053
+ const Server = `The "${this.id}" server`;
1054
+ const message = redactServerText(error instanceof Error ? error.message : String(error), this.config);
1055
+ const log = (line: string) => console.error(`MCP server "${this.id}" ${line}`);
1056
+ const listing = record.method === 'tools/list';
1057
+ // What a failure whose effect is in doubt says: for a tool call, that the
1058
+ // effect is unknown and to check it; for a listing, that it's safe to ask
1059
+ // again.
1060
+ const unknown = (said: string) => listing
1061
+ ? `${said}. Listing changes nothing on the server, so it's safe to try again.`
1062
+ : `${said}, so whether the request took effect is unknown. Check its effect before trying again.`;
1063
+ if (!record.handedOff) {
1064
+ log(`${what} not sent: ${logDetail(message)}`);
1065
+ const pipe = error instanceof NotWrittenError && error.pipe;
1066
+ return new McplRequestError(
1067
+ pipe
1068
+ ? `The request wasn't sent: this host can no longer write to ${server}, so nothing ran. ${this.retryText()}`
1069
+ // Before the wire, the cause can pass (the stdio line closing as
1070
+ // the connection is lost) or stay (a tool's outputSchema the SDK
1071
+ // can't compile), so the message claims neither.
1072
+ : `The request wasn't sent: this host couldn't send it to ${server}, so nothing ran. If calling it again fails, ask whoever runs this host.`,
1073
+ 'not-sent',
1074
+ );
1075
+ }
1076
+ if (record.answer === 'error' && record.error) {
1077
+ const { code, message: wireMessage, data } = record.error;
1078
+ // A JSON-RPC answer reaches the caller unredacted (redactServerText's
1079
+ // scope). The log is a record of the server's text, so the message is
1080
+ // redacted there, whatever JSON value it is, as every other line this
1081
+ // connection writes is.
1082
+ log(`answered ${what} with error ${logValue(code)}: ${logValueRedacted(wireMessage, (text) => redactServerText(text, this.config))}`);
1083
+ // The server's own words, bounded as errors.ts says. Only a string is
1084
+ // words: a message of any other JSON value reads as none.
1085
+ const said = typeof wireMessage === 'string' ? boundedForLog(wireMessage.trim()) : '';
1086
+ return new McplRequestError(
1087
+ said ? `${Server} answered with an error: ${said}` : unknown(`${Server} answered with an error without saying what went wrong`),
1088
+ 'error-response',
1089
+ data,
1090
+ );
1091
+ }
1092
+ if (record.answer === 'complete') {
1093
+ log(`answered ${what} with a result this host can't use: ${logDetail(message)}`);
1094
+ return new Error(unknown(`${Server} answered, but not in a form this host can read`));
1095
+ }
1096
+ const deadline = error instanceof SdkError && error.code === SdkErrorCode.RequestTimeout;
1097
+ const within = deadline && timeoutMs ? ` within ${timeoutMs}ms` : '';
1098
+ if (record.answer === 'input-required' || record.answer === 'unrecognized') {
1099
+ const reason = /[.!?]$/.test(message) ? message : `${message}.`;
1100
+ log(record.answer === 'unrecognized'
1101
+ ? `did not finish ${what}${within}: its answer was not a complete result: ${logDetail(reason)}`
1102
+ : deadline
1103
+ ? `did not finish ${what}${within}: it asked for another round (input_required), and the deadline passed before that round was sent`
1104
+ : `did not finish ${what}: it asked for another round (input_required), and the call ended before that round was sent: ${logDetail(reason)}`);
1105
+ return new McplRequestError(
1106
+ unknown(record.answer === 'unrecognized'
1107
+ ? `${Server}'s answer wasn't a complete result`
1108
+ : `${Server} didn't finish the request: it asked for more from this host, and ${deadline ? 'the time ran out' : 'the call ended'} before this host sent it`),
1109
+ 'no-response',
1110
+ );
1111
+ }
1112
+ // An HTTP refusal of the credential: 401 or 403, however the SDK raised
1113
+ // it. It raises a plain 403 under another code than its step-up limit's,
1114
+ // and an insufficient_scope 403 as InsufficientScopeError when no OAuth
1115
+ // provider is configured. A 403 can refuse a valid credential that lacks
1116
+ // permission, so the message says the server refused this host access.
1117
+ const refusedWith = error instanceof SdkHttpError && (error.status === 401 || error.status === 403)
1118
+ ? error.status
1119
+ : error instanceof InsufficientScopeError ? 403 : null;
1120
+ if (refusedWith !== null) {
1121
+ if (record.continued) {
1122
+ log(`refused a later round of ${what}: HTTP ${refusedWith} (${logDetail(message)})`);
1123
+ return new McplRequestError(
1124
+ listing
1125
+ ? unknown(`${Server} refused this host access partway through the request, after asking for more`)
1126
+ : `${Server} refused this host access partway through the request, after asking for more, so whether it took effect is unknown. ` +
1127
+ 'Check its effect before trying again; if calling it again fails, ask whoever runs this host.',
1128
+ 'no-response',
1129
+ );
1130
+ }
1131
+ log(`refused ${what}: HTTP ${refusedWith} (${logDetail(message)})`);
1132
+ // The response body (the SDK's `text`) is the server's text and can
1133
+ // echo the request's url, so it's left out of the data; the status stays.
1134
+ const { text: _body, ...data } = (error instanceof SdkHttpError && error.data && typeof error.data === 'object' ? error.data : {}) as Record<string, unknown>;
1135
+ return new McplRequestError(
1136
+ `${Server} refused this host access, so the request didn't run. If you need it, ask whoever runs this host.`,
1137
+ 'error-response',
1138
+ { ...data, httpStatus: refusedWith },
1139
+ );
1140
+ }
1141
+ if (deadline) {
1142
+ log(`didn't answer ${what}${within}; cancellation requested`);
1143
+ const seconds = timeoutMs ? timeoutMs / 1000 : null;
1144
+ const late = seconds === null ? `${Server} didn't answer in time` : `${Server} didn't answer within ${seconds} second${seconds === 1 ? '' : 's'}`;
1145
+ return new McplRequestError(
1146
+ listing
1147
+ ? `${late}, and this host asked it to cancel. Listing changes nothing on the server, so it's safe to try again.`
1148
+ : `${late}, so whether the request took effect is unknown: this host asked it to cancel, and it may still complete on the server. ` +
1149
+ 'Check its effect before trying again, since repeating something that changes state may do it twice.',
1150
+ 'no-response',
1151
+ );
1152
+ }
1153
+ // Anything else after the request went out. An HTTP status other than
1154
+ // 401/403 is only in the SDK's error, not its message, so the log names it.
1155
+ log(`${what} failed${error instanceof SdkHttpError ? ` with HTTP ${error.status}` : ''}: ${logDetail(message)}`);
1156
+ if (this.closedByHost) {
1157
+ // This host's close cut it off: the legacy engine's words.
1158
+ return new McplRequestError(unknown(`${Server} didn't answer before this host closed its connection`), 'no-response');
1159
+ }
1160
+ if (lost) {
1161
+ // The connection closed under it: the legacy engine's words, with
1162
+ // whether this host is reconnecting.
1163
+ return new McplRequestError(
1164
+ listing
1165
+ ? unknown(`The connection to ${server} closed before it answered`)
1166
+ : `The connection to ${server} closed before it answered, so whether the request took effect is unknown. ` +
1167
+ (this.willReconnect
1168
+ ? 'Check its effect before trying again; this host is reconnecting to it.'
1169
+ : "This host won't reconnect to it on its own. If you need it, ask whoever runs this host."),
1170
+ 'no-response',
1171
+ );
1172
+ }
1173
+ // The connection may still stand, as after an HTTP error with no JSON-RPC
1174
+ // answer, so the message says nothing of reconnecting.
1175
+ return new McplRequestError(
1176
+ listing
1177
+ ? `The request to ${server} failed before an answer came back. Listing changes nothing on the server, so it's safe to try again.`
1178
+ : `The request to ${server} failed before an answer came back, so whether it took effect is unknown. Check its effect before trying again.`,
1179
+ 'no-response',
1180
+ );
1181
+ }
1182
+ }