@gajae-code/coding-agent 0.17.1 → 0.17.4

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 (375) hide show
  1. package/CHANGELOG.md +266 -0
  2. package/dist/types/async/job-manager.d.ts +7 -6
  3. package/dist/types/cli/daemon-cli.d.ts +3 -1
  4. package/dist/types/cli/github-release.d.ts +17 -0
  5. package/dist/types/cli/public-command-entry.d.ts +56 -0
  6. package/dist/types/cli/public-command-errors.d.ts +126 -0
  7. package/dist/types/cli/public-command-evidence.d.ts +99 -0
  8. package/dist/types/cli/public-command-help.d.ts +65 -0
  9. package/dist/types/cli/public-command-registry.d.ts +69 -0
  10. package/dist/types/cli/session-picker.d.ts +1 -1
  11. package/dist/types/cli/setup-cli.d.ts +1 -0
  12. package/dist/types/cli/skills-cli.d.ts +5 -0
  13. package/dist/types/cli.d.ts +3 -0
  14. package/dist/types/commands/daemon.d.ts +4 -50
  15. package/dist/types/commands/sdk.d.ts +20 -37
  16. package/dist/types/commands/setup.d.ts +3 -0
  17. package/dist/types/commands/skills.d.ts +9 -0
  18. package/dist/types/config/autorouting-tier-map.d.ts +24 -0
  19. package/dist/types/config/file-lock.d.ts +10 -1
  20. package/dist/types/config/model-profile-activation.d.ts +63 -4
  21. package/dist/types/config/model-registry.d.ts +20 -2
  22. package/dist/types/config/settings-schema.d.ts +11 -0
  23. package/dist/types/coordinator-mcp/question-state.d.ts +6 -1
  24. package/dist/types/coordinator-mcp/server.d.ts +3 -0
  25. package/dist/types/daemon/operator-contract.d.ts +5 -1
  26. package/dist/types/eval/js/worker-protocol.d.ts +2 -0
  27. package/dist/types/extensibility/extensions/types.d.ts +12 -0
  28. package/dist/types/extensibility/gjc-plugins/registry.d.ts +4 -0
  29. package/dist/types/extensibility/runtime-skill-discovery.d.ts +18 -0
  30. package/dist/types/extensibility/shared-events.d.ts +3 -1
  31. package/dist/types/gjc-runtime/session-state-lock.d.ts +61 -0
  32. package/dist/types/internal-urls/embedded-protocol.d.ts +9 -0
  33. package/dist/types/internal-urls/index.d.ts +1 -0
  34. package/dist/types/internal-urls/parse.d.ts +9 -1
  35. package/dist/types/main.d.ts +22 -0
  36. package/dist/types/modes/acp/acp-agent.d.ts +94 -1
  37. package/dist/types/modes/acp/startup-provenance.d.ts +16 -0
  38. package/dist/types/modes/components/custom-provider-wizard.d.ts +19 -1
  39. package/dist/types/modes/components/session-selector.d.ts +5 -2
  40. package/dist/types/modes/components/thinking-selector.d.ts +2 -1
  41. package/dist/types/modes/components/user-message-selector.d.ts +5 -2
  42. package/dist/types/modes/controllers/command-controller.d.ts +1 -1
  43. package/dist/types/modes/controllers/selector-controller.d.ts +1 -1
  44. package/dist/types/modes/interactive-mode.d.ts +1 -1
  45. package/dist/types/modes/shared/agent-wire/workflow-gate-broker.d.ts +11 -1
  46. package/dist/types/modes/shared/agent-wire/workflow-gate-types.d.ts +14 -1
  47. package/dist/types/modes/types.d.ts +2 -2
  48. package/dist/types/runtime/process-lifecycle.d.ts +2 -0
  49. package/dist/types/runtime-mcp/manager.d.ts +56 -0
  50. package/dist/types/runtime-mcp/pool.d.ts +17 -0
  51. package/dist/types/runtime-mcp/redaction.d.ts +20 -0
  52. package/dist/types/runtime-mcp/startup-policy.d.ts +6 -0
  53. package/dist/types/runtime-mcp/tool-bridge.d.ts +9 -0
  54. package/dist/types/runtime-mcp/transports/http.d.ts +11 -0
  55. package/dist/types/sdk/acp/adapter.d.ts +27 -0
  56. package/dist/types/sdk/acp/final-text.d.ts +8 -0
  57. package/dist/types/sdk/broker/broker.d.ts +13 -2
  58. package/dist/types/sdk/broker/ensure.d.ts +46 -1
  59. package/dist/types/sdk/broker/identity.d.ts +3 -1
  60. package/dist/types/sdk/broker/lifecycle-ledger.d.ts +23 -3
  61. package/dist/types/sdk/broker/lifecycle.d.ts +15 -8
  62. package/dist/types/sdk/broker/runtime.d.ts +1 -1
  63. package/dist/types/sdk/broker/session-index.d.ts +22 -3
  64. package/dist/types/sdk/broker/spawn-authority.d.ts +4 -0
  65. package/dist/types/sdk/broker/stderr-drainer.d.ts +13 -0
  66. package/dist/types/sdk/bus/index.d.ts +19 -0
  67. package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +3 -1
  68. package/dist/types/sdk/bus/telegram-daemon.d.ts +5 -0
  69. package/dist/types/sdk/cli/master-cli.d.ts +6 -10
  70. package/dist/types/sdk/cli/rows.d.ts +19 -1
  71. package/dist/types/sdk/cli/session-cli.d.ts +22 -5
  72. package/dist/types/sdk/client/client.d.ts +2 -0
  73. package/dist/types/sdk/guides/cli.d.ts +3 -4
  74. package/dist/types/sdk/guides/verify.d.ts +2 -0
  75. package/dist/types/sdk/host/host.d.ts +9 -0
  76. package/dist/types/sdk/host/session-runtime.d.ts +31 -0
  77. package/dist/types/sdk/host/types.d.ts +10 -0
  78. package/dist/types/sdk/index.d.ts +1 -0
  79. package/dist/types/sdk/prompt-deadline-flush.d.ts +83 -0
  80. package/dist/types/sdk/prompt-deadline-manager.d.ts +38 -1
  81. package/dist/types/sdk/prompt-failure.d.ts +30 -1
  82. package/dist/types/sdk/prompt-status.d.ts +8 -0
  83. package/dist/types/sdk/prompt-tool-boundary.d.ts +73 -0
  84. package/dist/types/sdk/router/replay-retention-gap-cache.d.ts +13 -0
  85. package/dist/types/sdk/router/session-router.d.ts +2 -0
  86. package/dist/types/sdk/startup-capability.d.ts +2 -0
  87. package/dist/types/sdk/transport/relay.d.ts +1 -0
  88. package/dist/types/sdk/transport/serve-cli.d.ts +73 -2
  89. package/dist/types/sdk/transport/stdio.d.ts +5 -1
  90. package/dist/types/session/agent-session.d.ts +168 -21
  91. package/dist/types/session/fallback-chain-controller.d.ts +6 -6
  92. package/dist/types/session/fold-coordinator.d.ts +17 -3
  93. package/dist/types/session/internal/managed-session-storage.d.ts +7 -1
  94. package/dist/types/session/session-manager.d.ts +64 -1
  95. package/dist/types/session/session-work-lease.d.ts +14 -0
  96. package/dist/types/setup/model-onboarding-guidance.d.ts +1 -1
  97. package/dist/types/setup/provider-onboarding.d.ts +81 -1
  98. package/dist/types/thinking.d.ts +3 -1
  99. package/dist/types/tools/bash.d.ts +37 -11
  100. package/dist/types/tools/job.d.ts +1 -1
  101. package/dist/types/tools/steer-fold.d.ts +31 -0
  102. package/dist/types/utils/git.d.ts +28 -2
  103. package/dist/types/utils/mupdf-embedded.d.ts +2 -0
  104. package/dist/types/utils/mupdf-wasm-embedded.d.ts +2 -0
  105. package/dist/types/utils/mupdf.d.ts +4 -0
  106. package/dist/types/utils/session-title-generation.d.ts +6 -0
  107. package/dist/types/utils/title-generator.d.ts +11 -2
  108. package/dist/types/web/scrapers/types.d.ts +3 -0
  109. package/package.json +18 -10
  110. package/scripts/build-binary.ts +9 -3
  111. package/scripts/compile-args.ts +0 -9
  112. package/scripts/embed-mupdf.ts +52 -0
  113. package/scripts/generate-sdk-operation-inventory.ts +31 -1
  114. package/scripts/vendor-markit.ts +196 -0
  115. package/src/async/job-manager.ts +60 -9
  116. package/src/cli/daemon-cli.ts +53 -18
  117. package/src/cli/github-release.ts +87 -5
  118. package/src/cli/mcp-cli.ts +38 -4
  119. package/src/cli/public-command-entry.ts +450 -0
  120. package/src/cli/public-command-errors.ts +581 -0
  121. package/src/cli/public-command-evidence.ts +717 -0
  122. package/src/cli/public-command-help.ts +360 -0
  123. package/src/cli/public-command-registry.ts +535 -0
  124. package/src/cli/session-picker.ts +2 -1
  125. package/src/cli/setup-cli.ts +9 -1
  126. package/src/cli/skills-cli.ts +46 -2
  127. package/src/cli.ts +61 -1
  128. package/src/commands/daemon.ts +65 -69
  129. package/src/commands/sdk.ts +232 -100
  130. package/src/commands/setup.ts +2 -0
  131. package/src/commands/skills.ts +11 -0
  132. package/src/config/autorouting-tier-map.ts +16 -0
  133. package/src/config/file-lock.ts +199 -68
  134. package/src/config/model-profile-activation.ts +406 -53
  135. package/src/config/model-registry.ts +204 -25
  136. package/src/config/settings-schema.ts +26 -2
  137. package/src/coordinator-mcp/policy.ts +10 -5
  138. package/src/coordinator-mcp/question-gate-codec.ts +17 -0
  139. package/src/coordinator-mcp/question-state.ts +175 -8
  140. package/src/coordinator-mcp/server.ts +528 -87
  141. package/src/coordinator-mcp/session-reaper.ts +6 -4
  142. package/src/crash/record-loader.ts +6 -2
  143. package/src/daemon/operator-contract.ts +26 -12
  144. package/src/debug/report-bundle.ts +114 -24
  145. package/src/defaults/gjc/skills/ultragoal/SKILL.md +1 -1
  146. package/src/eval/js/context-manager.ts +8 -8
  147. package/src/eval/js/worker-core.ts +9 -4
  148. package/src/eval/js/worker-protocol.ts +2 -0
  149. package/src/extensibility/extensions/runner.ts +52 -4
  150. package/src/extensibility/extensions/types.ts +10 -0
  151. package/src/extensibility/gjc-plugins/registry.ts +196 -37
  152. package/src/extensibility/runtime-skill-discovery.ts +61 -3
  153. package/src/extensibility/shared-events.ts +3 -1
  154. package/src/gjc-runtime/managed-owner-admission.ts +67 -50
  155. package/src/gjc-runtime/session-state-lock.ts +165 -24
  156. package/src/gjc-runtime/ultragoal-succession.ts +31 -3
  157. package/src/internal-urls/docs-index.generated.ts +21 -19
  158. package/src/internal-urls/embedded-protocol.ts +83 -0
  159. package/src/internal-urls/index.ts +1 -0
  160. package/src/internal-urls/parse.ts +21 -1
  161. package/src/internal-urls/router.ts +4 -2
  162. package/src/main.ts +123 -55
  163. package/src/modes/acp/acp-agent.ts +593 -47
  164. package/src/modes/acp/acp-event-mapper.ts +9 -0
  165. package/src/modes/acp/startup-provenance.ts +59 -0
  166. package/src/modes/components/custom-provider-wizard.ts +308 -7
  167. package/src/modes/components/model-selector.ts +31 -15
  168. package/src/modes/components/oauth-selector.ts +9 -0
  169. package/src/modes/components/session-selector.ts +47 -4
  170. package/src/modes/components/status-line/segments.ts +6 -1
  171. package/src/modes/components/thinking-selector.ts +7 -3
  172. package/src/modes/components/user-message-selector.ts +57 -15
  173. package/src/modes/controllers/command-controller.ts +58 -32
  174. package/src/modes/controllers/extension-ui-controller.ts +33 -7
  175. package/src/modes/controllers/input-controller.ts +4 -0
  176. package/src/modes/controllers/selector-controller.ts +177 -18
  177. package/src/modes/interactive-mode.ts +21 -7
  178. package/src/modes/runtime-init.ts +1 -0
  179. package/src/modes/shared/agent-wire/workflow-gate-broker.ts +124 -7
  180. package/src/modes/shared/agent-wire/workflow-gate-types.ts +16 -2
  181. package/src/modes/types.ts +2 -2
  182. package/src/prompts/agent-fragments/browser-aside.md +1 -0
  183. package/src/prompts/system/title-system.md +1 -1
  184. package/src/prompts/tools/bash.md +1 -1
  185. package/src/prompts/tools/job.md +1 -1
  186. package/src/prompts/tools/read.md +2 -0
  187. package/src/runtime/network-prewarm-service.test.ts +36 -1
  188. package/src/runtime/network-prewarm-service.ts +28 -3
  189. package/src/runtime/process-lifecycle.ts +22 -11
  190. package/src/runtime-mcp/config.ts +16 -1
  191. package/src/runtime-mcp/manager.ts +689 -55
  192. package/src/runtime-mcp/pool.test.ts +31 -0
  193. package/src/runtime-mcp/pool.ts +304 -28
  194. package/src/runtime-mcp/redaction.ts +42 -0
  195. package/src/runtime-mcp/startup-policy.ts +7 -0
  196. package/src/runtime-mcp/tool-bridge.ts +71 -0
  197. package/src/runtime-mcp/transports/http.ts +108 -25
  198. package/src/sdk/acp/adapter.ts +90 -9
  199. package/src/sdk/acp/final-text.ts +19 -2
  200. package/src/sdk/broker/broker.ts +378 -52
  201. package/src/sdk/broker/ensure.ts +97 -19
  202. package/src/sdk/broker/identity.ts +9 -1
  203. package/src/sdk/broker/lifecycle-ledger.ts +95 -31
  204. package/src/sdk/broker/lifecycle.ts +690 -141
  205. package/src/sdk/broker/runtime.ts +1 -1
  206. package/src/sdk/broker/session-index.ts +97 -4
  207. package/src/sdk/broker/spawn-authority.ts +35 -7
  208. package/src/sdk/broker/stderr-drainer.ts +59 -0
  209. package/src/sdk/bus/chat-daemon-control.ts +2 -2
  210. package/src/sdk/bus/chat-daemon-runtime.ts +1 -0
  211. package/src/sdk/bus/index.ts +721 -84
  212. package/src/sdk/bus/telegram-daemon-cli.ts +31 -2
  213. package/src/sdk/bus/telegram-daemon-contract.ts +3 -1
  214. package/src/sdk/bus/telegram-daemon.ts +10 -3
  215. package/src/sdk/cli/master-cli.ts +47 -36
  216. package/src/sdk/cli/rows.ts +30 -7
  217. package/src/sdk/cli/session-cli.ts +687 -184
  218. package/src/sdk/client/client.ts +18 -0
  219. package/src/sdk/guides/catalog.ts +2 -2
  220. package/src/sdk/guides/cli.ts +20 -62
  221. package/src/sdk/guides/verify.ts +14 -0
  222. package/src/sdk/host/host.ts +49 -5
  223. package/src/sdk/host/session-runtime.test.ts +636 -9
  224. package/src/sdk/host/session-runtime.ts +499 -118
  225. package/src/sdk/host/types.ts +12 -1
  226. package/src/sdk/host/websocket-transport.lifecycle.test.ts +84 -0
  227. package/src/sdk/host/websocket-transport.ts +40 -6
  228. package/src/sdk/index.ts +11 -0
  229. package/src/sdk/prompt-deadline-flush.ts +334 -0
  230. package/src/sdk/prompt-deadline-manager.ts +136 -4
  231. package/src/sdk/prompt-failure.ts +43 -1
  232. package/src/sdk/prompt-status.ts +8 -0
  233. package/src/sdk/prompt-tool-boundary.ts +121 -0
  234. package/src/sdk/protocol/operation-inventory.generated.json +106 -0
  235. package/src/sdk/router/replay-retention-gap-cache.ts +27 -0
  236. package/src/sdk/router/session-router.ts +31 -4
  237. package/src/sdk/session.ts +194 -16
  238. package/src/sdk/startup-capability.ts +1 -1
  239. package/src/sdk/transport/relay.ts +71 -6
  240. package/src/sdk/transport/serve-cli.ts +494 -49
  241. package/src/sdk/transport/socket.ts +12 -11
  242. package/src/sdk/transport/stdio.ts +7 -3
  243. package/src/session/agent-session.ts +2437 -400
  244. package/src/session/fallback-chain-controller.ts +6 -7
  245. package/src/session/fold-coordinator.ts +24 -5
  246. package/src/session/internal/managed-session-scope.ts +58 -18
  247. package/src/session/internal/managed-session-storage.ts +304 -11
  248. package/src/session/session-manager.ts +382 -44
  249. package/src/session/session-work-lease.ts +34 -0
  250. package/src/session-import/codex.ts +12 -3
  251. package/src/setup/model-onboarding-guidance.ts +1 -1
  252. package/src/setup/provider-onboarding.ts +397 -24
  253. package/src/slash-commands/builtin-registry.ts +258 -14
  254. package/src/task/index.ts +14 -2
  255. package/src/thinking.ts +21 -2
  256. package/src/tools/bash.ts +98 -78
  257. package/src/tools/fetch.ts +119 -20
  258. package/src/tools/job.ts +151 -25
  259. package/src/tools/output-meta.ts +15 -2
  260. package/src/tools/path-utils.ts +27 -3
  261. package/src/tools/read.ts +3 -3
  262. package/src/tools/steer-fold.ts +107 -0
  263. package/src/tools/tool-catalog.generated.ts +29 -2
  264. package/src/tools/tool-errors.ts +4 -0
  265. package/src/utils/git.ts +53 -3
  266. package/src/utils/markit.ts +55 -41
  267. package/src/utils/mupdf-assets.d.ts +4 -0
  268. package/src/utils/mupdf-embedded.ts +4 -0
  269. package/src/utils/mupdf-wasm-embedded.ts +3 -0
  270. package/src/utils/mupdf-wasm.ts +24 -2
  271. package/src/utils/mupdf.ts +129 -0
  272. package/src/utils/session-title-generation.ts +29 -0
  273. package/src/utils/title-generator.ts +46 -2
  274. package/src/web/scrapers/types.ts +24 -3
  275. package/vendor/markit-ai/LICENSE +21 -0
  276. package/vendor/markit-ai/MANIFEST.json +412 -0
  277. package/vendor/markit-ai/dist/commands/config.d.ts +4 -0
  278. package/vendor/markit-ai/dist/commands/config.js +139 -0
  279. package/vendor/markit-ai/dist/commands/convert.d.ts +6 -0
  280. package/vendor/markit-ai/dist/commands/convert.js +113 -0
  281. package/vendor/markit-ai/dist/commands/formats.d.ts +2 -0
  282. package/vendor/markit-ai/dist/commands/formats.js +92 -0
  283. package/vendor/markit-ai/dist/commands/init.d.ts +2 -0
  284. package/vendor/markit-ai/dist/commands/init.js +29 -0
  285. package/vendor/markit-ai/dist/commands/onboard.d.ts +2 -0
  286. package/vendor/markit-ai/dist/commands/onboard.js +61 -0
  287. package/vendor/markit-ai/dist/commands/plugin.d.ts +4 -0
  288. package/vendor/markit-ai/dist/commands/plugin.js +58 -0
  289. package/vendor/markit-ai/dist/config.d.ts +26 -0
  290. package/vendor/markit-ai/dist/config.js +42 -0
  291. package/vendor/markit-ai/dist/converters/audio.d.ts +7 -0
  292. package/vendor/markit-ai/dist/converters/audio.js +104 -0
  293. package/vendor/markit-ai/dist/converters/csv.d.ts +7 -0
  294. package/vendor/markit-ai/dist/converters/csv.js +83 -0
  295. package/vendor/markit-ai/dist/converters/docx.d.ts +6 -0
  296. package/vendor/markit-ai/dist/converters/docx.js +57 -0
  297. package/vendor/markit-ai/dist/converters/epub.d.ts +8 -0
  298. package/vendor/markit-ai/dist/converters/epub.js +128 -0
  299. package/vendor/markit-ai/dist/converters/github.d.ts +18 -0
  300. package/vendor/markit-ai/dist/converters/github.js +148 -0
  301. package/vendor/markit-ai/dist/converters/html.d.ts +6 -0
  302. package/vendor/markit-ai/dist/converters/html.js +30 -0
  303. package/vendor/markit-ai/dist/converters/image.d.ts +6 -0
  304. package/vendor/markit-ai/dist/converters/image.js +124 -0
  305. package/vendor/markit-ai/dist/converters/ipynb.d.ts +6 -0
  306. package/vendor/markit-ai/dist/converters/ipynb.js +75 -0
  307. package/vendor/markit-ai/dist/converters/iwork.d.ts +20 -0
  308. package/vendor/markit-ai/dist/converters/iwork.js +391 -0
  309. package/vendor/markit-ai/dist/converters/json.d.ts +6 -0
  310. package/vendor/markit-ai/dist/converters/json.js +21 -0
  311. package/vendor/markit-ai/dist/converters/pdf/columns.d.ts +35 -0
  312. package/vendor/markit-ai/dist/converters/pdf/columns.js +93 -0
  313. package/vendor/markit-ai/dist/converters/pdf/extract.d.ts +19 -0
  314. package/vendor/markit-ai/dist/converters/pdf/extract.js +514 -0
  315. package/vendor/markit-ai/dist/converters/pdf/grid.d.ts +25 -0
  316. package/vendor/markit-ai/dist/converters/pdf/grid.js +795 -0
  317. package/vendor/markit-ai/dist/converters/pdf/headers.d.ts +24 -0
  318. package/vendor/markit-ai/dist/converters/pdf/headers.js +108 -0
  319. package/vendor/markit-ai/dist/converters/pdf/index.d.ts +19 -0
  320. package/vendor/markit-ai/dist/converters/pdf/index.js +136 -0
  321. package/vendor/markit-ai/dist/converters/pdf/mupdf-loader.js +9 -0
  322. package/vendor/markit-ai/dist/converters/pdf/render.d.ts +24 -0
  323. package/vendor/markit-ai/dist/converters/pdf/render.js +513 -0
  324. package/vendor/markit-ai/dist/converters/pdf/types.d.ts +75 -0
  325. package/vendor/markit-ai/dist/converters/pdf/types.js +1 -0
  326. package/vendor/markit-ai/dist/converters/plain-text.d.ts +6 -0
  327. package/vendor/markit-ai/dist/converters/plain-text.js +87 -0
  328. package/vendor/markit-ai/dist/converters/pptx.d.ts +8 -0
  329. package/vendor/markit-ai/dist/converters/pptx.js +289 -0
  330. package/vendor/markit-ai/dist/converters/rss.d.ts +11 -0
  331. package/vendor/markit-ai/dist/converters/rss.js +138 -0
  332. package/vendor/markit-ai/dist/converters/wikipedia.d.ts +6 -0
  333. package/vendor/markit-ai/dist/converters/wikipedia.js +33 -0
  334. package/vendor/markit-ai/dist/converters/xlsx.d.ts +8 -0
  335. package/vendor/markit-ai/dist/converters/xlsx.js +147 -0
  336. package/vendor/markit-ai/dist/converters/xml.d.ts +6 -0
  337. package/vendor/markit-ai/dist/converters/xml.js +18 -0
  338. package/vendor/markit-ai/dist/converters/yaml.d.ts +6 -0
  339. package/vendor/markit-ai/dist/converters/yaml.js +17 -0
  340. package/vendor/markit-ai/dist/converters/zip.d.ts +8 -0
  341. package/vendor/markit-ai/dist/converters/zip.js +57 -0
  342. package/vendor/markit-ai/dist/index.d.ts +30 -0
  343. package/vendor/markit-ai/dist/index.js +26 -0
  344. package/vendor/markit-ai/dist/main.d.ts +2 -0
  345. package/vendor/markit-ai/dist/main.js +191 -0
  346. package/vendor/markit-ai/dist/markit.d.ts +45 -0
  347. package/vendor/markit-ai/dist/markit.js +267 -0
  348. package/vendor/markit-ai/dist/plugins/api.d.ts +7 -0
  349. package/vendor/markit-ai/dist/plugins/api.js +42 -0
  350. package/vendor/markit-ai/dist/plugins/index.d.ts +4 -0
  351. package/vendor/markit-ai/dist/plugins/index.js +3 -0
  352. package/vendor/markit-ai/dist/plugins/installer.d.ts +25 -0
  353. package/vendor/markit-ai/dist/plugins/installer.js +176 -0
  354. package/vendor/markit-ai/dist/plugins/loader.d.ts +6 -0
  355. package/vendor/markit-ai/dist/plugins/loader.js +61 -0
  356. package/vendor/markit-ai/dist/plugins/types.d.ts +25 -0
  357. package/vendor/markit-ai/dist/plugins/types.js +1 -0
  358. package/vendor/markit-ai/dist/providers/anthropic.d.ts +2 -0
  359. package/vendor/markit-ai/dist/providers/anthropic.js +47 -0
  360. package/vendor/markit-ai/dist/providers/index.d.ts +21 -0
  361. package/vendor/markit-ai/dist/providers/index.js +56 -0
  362. package/vendor/markit-ai/dist/providers/openai.d.ts +2 -0
  363. package/vendor/markit-ai/dist/providers/openai.js +76 -0
  364. package/vendor/markit-ai/dist/providers/types.d.ts +26 -0
  365. package/vendor/markit-ai/dist/providers/types.js +1 -0
  366. package/vendor/markit-ai/dist/types.d.ts +36 -0
  367. package/vendor/markit-ai/dist/types.js +1 -0
  368. package/vendor/markit-ai/dist/utils/exit-codes.d.ts +4 -0
  369. package/vendor/markit-ai/dist/utils/exit-codes.js +4 -0
  370. package/vendor/markit-ai/dist/utils/output.d.ts +22 -0
  371. package/vendor/markit-ai/dist/utils/output.js +31 -0
  372. package/vendor/markit-ai/dist/utils/turndown.d.ts +8 -0
  373. package/vendor/markit-ai/dist/utils/turndown.js +70 -0
  374. package/vendor/markit-ai/package.json +74 -0
  375. package/vendor/markit-ai.patch +49 -0
@@ -35,6 +35,7 @@ import {
35
35
  MCPPoolLeaseReleaseError,
36
36
  } from "./pool";
37
37
  import type { MCPProtocolObservation } from "./protocol";
38
+ import { DEFAULT_MCP_STARTUP_WAIT_MS, MAX_MCP_STARTUP_WAIT_MS, MCP_STARTUP_WAIT_GRACE_MS } from "./startup-policy";
38
39
  import type { MCPToolDetails } from "./tool-bridge";
39
40
  import { DeferredMCPTool, MCPTool } from "./tool-bridge";
40
41
  import type { MCPToolCache } from "./tool-cache";
@@ -101,16 +102,23 @@ type RetiredLeaseRelease = {
101
102
  promise: Promise<void>;
102
103
  };
103
104
 
104
- const STARTUP_TIMEOUT_MS = 250;
105
- const STARTUP_TIMEOUT_GRACE_MS = 500;
105
+ const STARTUP_TIMEOUT_MS = DEFAULT_MCP_STARTUP_WAIT_MS;
106
+ const STARTUP_TIMEOUT_GRACE_MS = MCP_STARTUP_WAIT_GRACE_MS;
106
107
  /**
107
108
  * Default ceiling on how long `discoverAndConnect` waits for a server batch to
108
109
  * come up. Deliberately short: a config with a large `timeout` must not be able
109
110
  * to hang ordinary startup. ACP lifecycle launches carry their own, larger
110
111
  * budget derived from the readiness deadline (see `maxStartupTimeoutMs`).
111
112
  */
112
- const MAX_STARTUP_TIMEOUT_MS = 1_750;
113
+ const MAX_STARTUP_TIMEOUT_MS = MAX_MCP_STARTUP_WAIT_MS;
113
114
  const DEFAULT_EXACT_CONFIG_STARTUP_TIMEOUT_MS = 30_000;
115
+ const MCP_STARTUP_TIMEOUT_PREFIX = "MCP server connection timed out during startup:";
116
+
117
+ export function isMCPStartupTimeoutError(error: unknown): boolean {
118
+ return typeof error === "string"
119
+ ? error.startsWith(MCP_STARTUP_TIMEOUT_PREFIX)
120
+ : error instanceof Error && error.message.startsWith(MCP_STARTUP_TIMEOUT_PREFIX);
121
+ }
114
122
 
115
123
  export function resolveStartupTimeoutMs(configs: MCPServerConfig[], maxStartupTimeoutMs?: number): number {
116
124
  const ceiling =
@@ -260,6 +268,22 @@ export interface MCPLoadResult {
260
268
  exaApiKeys: string[];
261
269
  }
262
270
 
271
+ export type MCPToolCatalogPublication = "unpublished" | "published" | "fenced";
272
+
273
+ /**
274
+ * Atomic view of the manager's fenced tool catalog and its publication state.
275
+ *
276
+ * `unpublished` is reserved for the initial deferred window where no manager
277
+ * catalog has been published and no exact control is fencing it. An empty
278
+ * `published` or `fenced` catalog is authoritative and must not be replaced
279
+ * with an in-flight discovery result.
280
+ */
281
+ export interface MCPToolCatalogSnapshot {
282
+ tools: CustomTool<TSchema, MCPToolDetails>[];
283
+ publication: MCPToolCatalogPublication;
284
+ generation: number;
285
+ }
286
+
263
287
  /** Options for discovering and connecting to MCP servers */
264
288
  export interface MCPDiscoverOptions {
265
289
  /** Whether to load project-level config (default: true) */
@@ -306,6 +330,41 @@ export interface MCPManagerOptions {
306
330
  afterLeaseAcquiredForTests?: (name: string, lease: MCPPoolLease) => void | Promise<void>;
307
331
  }
308
332
 
333
+ export type ExactMcpServerControlStatus =
334
+ | "suspended"
335
+ | "already-suspended"
336
+ | "resumed"
337
+ | "not-suspended"
338
+ | "reconnected"
339
+ | "unavailable"
340
+ | "unknown-server";
341
+
342
+ export interface ExactMcpServerControlResult {
343
+ readonly name: string;
344
+ readonly status: ExactMcpServerControlStatus;
345
+ readonly toolCount: number;
346
+ }
347
+
348
+ /**
349
+ * A staged catalog the caller can validate against before it is published.
350
+ * `commit` is the single publication point; `abort` releases anything the
351
+ * preparation opened and leaves the manager on its predecessor.
352
+ */
353
+ export interface PreparedExactMcpCatalog {
354
+ readonly tools: CustomTool<TSchema, MCPToolDetails>[];
355
+ canCommit(): boolean;
356
+ commit(): Promise<void>;
357
+ abort(): Promise<void>;
358
+ }
359
+
360
+ export interface PreparedExactMcpServerControl extends PreparedExactMcpCatalog {
361
+ readonly result: ExactMcpServerControlResult;
362
+ /** Validate a resumed replacement before an atomic multi-server publication. */
363
+ precommit?(): void;
364
+ /** Publish after every replacement in the catalog has passed precommit. */
365
+ publish?(): void;
366
+ }
367
+
309
368
  /**
310
369
  * MCP Server Manager.
311
370
  *
@@ -342,6 +401,8 @@ export class MCPManager {
342
401
  readonly #retiredLeaseReleases = new Set<RetiredLeaseRelease>();
343
402
  #nextScopedOperationId = 1;
344
403
  #tools: CustomTool<TSchema, MCPToolDetails>[] = [];
404
+ #toolCatalogGeneration = 0;
405
+ #toolCatalogPublished = false;
345
406
  #pendingConnections = new Map<string, Promise<MCPServerConnection>>();
346
407
  #pendingConnectionControllers = new Map<string, AbortController>();
347
408
  #pendingToolLoads = new Map<string, Promise<ToolLoadResult>>();
@@ -365,6 +426,13 @@ export class MCPManager {
365
426
  #reconnectBackoffs = new Map<string, AbortController>();
366
427
  /** Preserved configs for reconnection after connection loss. */
367
428
  #serverConfigs = new Map<string, MCPServerConfig>();
429
+ // Exact MCP replacements retain cleanup ownership and cancel in-flight candidates.
430
+ /** Session-local operator suppression; never persisted to MCP config. */
431
+ #suppressedServers = new Set<string>();
432
+ /** Prepare-phase fence that prevents a concurrent close/rebind publication. */
433
+ #pendingExactSuspensions = new Set<string>();
434
+ /** Single per-server candidate axis shared against automatic reconnect. */
435
+ #pendingExactControlServers = new Set<string>();
368
436
  /** Monotonic epoch incremented on disconnectAll to invalidate stale reconnections. */
369
437
  #epoch = 0;
370
438
  #scopedLifecycle: "open" | "disconnecting" | "reconnecting" = "open";
@@ -539,7 +607,11 @@ export class MCPManager {
539
607
  }
540
608
 
541
609
  #scheduleSharedRebind(name: string, lease: MCPPoolLease): void {
542
- if (this.#scopedLifecycle === "disconnecting") return;
610
+ if (this.#pendingExactSuspensions.has(name) || this.#pendingExactControlServers.has(name)) {
611
+ this.#queueDeferredSharedRebind(name, lease, this.#epoch);
612
+ return;
613
+ }
614
+ if (this.#scopedLifecycle === "disconnecting" || this.#suppressedServers.has(name)) return;
543
615
  const active = this.#activeSharedRebinds.get(name);
544
616
  if (active) {
545
617
  if (active.lease !== lease) this.#queueDeferredSharedRebind(name, lease, this.#epoch);
@@ -562,6 +634,15 @@ export class MCPManager {
562
634
  #drainDeferredSharedRebinds(): void {
563
635
  if (this.#scopedLifecycle !== "open" || this.#deferredSharedRebinds.size === 0) return;
564
636
  for (const [name, pending] of this.#deferredSharedRebinds.entries()) {
637
+ // A suspended or in-flight control still owns this server. Keep the newest
638
+ // replacement queued so the manager rebinds after suppression clears instead
639
+ // of staying bound to a retired pool generation.
640
+ if (
641
+ this.#suppressedServers.has(name) ||
642
+ this.#pendingExactSuspensions.has(name) ||
643
+ this.#pendingExactControlServers.has(name)
644
+ )
645
+ continue;
565
646
  if (pending.managerEpoch !== this.#epoch) {
566
647
  this.#deferredSharedRebinds.delete(name);
567
648
  continue;
@@ -614,7 +695,14 @@ export class MCPManager {
614
695
  this.#handleServerNotification(name, event.method, event.params);
615
696
  return;
616
697
  }
617
- if (event.type !== "close" || this.#connectionSetSealed) return;
698
+ if (
699
+ event.type !== "close" ||
700
+ this.#connectionSetSealed ||
701
+ this.#suppressedServers.has(name) ||
702
+ this.#pendingExactSuspensions.has(name) ||
703
+ this.#pendingExactControlServers.has(name)
704
+ )
705
+ return;
618
706
  void this.reconnectServer(name);
619
707
  }),
620
708
  );
@@ -622,7 +710,12 @@ export class MCPManager {
622
710
 
623
711
  async #rebindAfterSharedRestart(name: string, lease: MCPPoolLease): Promise<void> {
624
712
  const managerEpoch = this.#epoch;
625
- if (this.#scopedLifecycle === "disconnecting") return;
713
+ if (
714
+ this.#scopedLifecycle === "disconnecting" ||
715
+ this.#pendingExactSuspensions.has(name) ||
716
+ this.#pendingExactControlServers.has(name)
717
+ )
718
+ return;
626
719
  if (this.#scopedLifecycle === "reconnecting") {
627
720
  this.#queueDeferredSharedRebind(name, lease, managerEpoch);
628
721
  return;
@@ -1067,6 +1160,13 @@ export class MCPManager {
1067
1160
  "MCP connection cleanup pending";
1068
1161
  errors.set(name, this.#serverError(message));
1069
1162
  reportedErrors.add(name);
1163
+ if (!this.#toolsOnly) {
1164
+ logger.warn("Skipping MCP autoload registration", {
1165
+ path: `mcp:${name}`,
1166
+ serverName: name,
1167
+ reason: message,
1168
+ });
1169
+ }
1070
1170
  continue;
1071
1171
  }
1072
1172
  if (sources[name]) {
@@ -1080,11 +1180,14 @@ export class MCPManager {
1080
1180
  // Skip if already connected.
1081
1181
  if (this.#connections.has(name)) {
1082
1182
  connectedServers.add(name);
1083
- allTools.push(
1084
- ...this.#tools.filter(
1085
- tool => (tool instanceof MCPTool || tool instanceof DeferredMCPTool) && tool.mcpServerName === name,
1086
- ),
1087
- );
1183
+ if (this.#isExactToolPublicationAllowed(name)) {
1184
+ allTools.push(
1185
+ ...this.#tools.filter(
1186
+ tool =>
1187
+ (tool instanceof MCPTool || tool instanceof DeferredMCPTool) && tool.mcpServerName === name,
1188
+ ),
1189
+ );
1190
+ }
1088
1191
  continue;
1089
1192
  }
1090
1193
 
@@ -1093,14 +1196,29 @@ export class MCPManager {
1093
1196
  this.#pendingToolLoads.has(name) ||
1094
1197
  this.#pendingReconnections.has(name)
1095
1198
  ) {
1199
+ if (!this.#toolsOnly) {
1200
+ logger.warn("Skipping MCP autoload registration", {
1201
+ path: `mcp:${name}`,
1202
+ serverName: name,
1203
+ reason: "connection already pending",
1204
+ });
1205
+ }
1096
1206
  continue;
1097
1207
  }
1098
1208
 
1099
1209
  // Validate config
1100
1210
  const validationErrors = validateServerConfig(name, config);
1101
1211
  if (validationErrors.length > 0) {
1102
- errors.set(name, this.#serverError(validationErrors.join("; ")));
1212
+ const reason = validationErrors.join("; ");
1213
+ errors.set(name, this.#serverError(reason));
1103
1214
  reportedErrors.add(name);
1215
+ if (!this.#toolsOnly) {
1216
+ logger.warn("Skipping MCP autoload registration", {
1217
+ path: `mcp:${name}`,
1218
+ serverName: name,
1219
+ reason,
1220
+ });
1221
+ }
1104
1222
  continue;
1105
1223
  }
1106
1224
 
@@ -1237,10 +1355,12 @@ export class MCPManager {
1237
1355
  return;
1238
1356
  this.#pendingToolLoads.delete(name);
1239
1357
  const reconnect = () => this.reconnectServer(name);
1240
- const customTools = MCPTool.fromTools(this.#connectionForLease(connection), serverTools, reconnect, {
1241
- noReplay: config.sharing === "shared",
1242
- inputHandler: () => this.#inputRequestHandler ?? undefined,
1243
- });
1358
+ const customTools = MCPTool.fromTools(
1359
+ this.#connectionForLease(connection),
1360
+ serverTools,
1361
+ reconnect,
1362
+ this.#exactToolOptions(name, config.sharing === "shared"),
1363
+ );
1244
1364
  this.#replaceServerTools(name, customTools);
1245
1365
  if (!this.#toolsOnly) this.#onToolsChanged?.(this.#tools);
1246
1366
  if (!this.#toolsOnly) void this.toolCache?.set(name, config, serverTools);
@@ -1250,9 +1370,11 @@ export class MCPManager {
1250
1370
  this.#retainConnectionCleanupFailure(name, error);
1251
1371
  if (this.#pendingToolLoads.get(name) !== toolsPromise) return;
1252
1372
  this.#pendingToolLoads.delete(name);
1253
- if (!allowBackgroundLogging || reportedErrors.has(name) || this.#toolsOnly) return;
1373
+ if (!allowBackgroundLogging || this.#toolsOnly || reportedErrors.has(name)) return;
1254
1374
  const message = error instanceof Error ? error.message : String(error);
1255
- logger.error("MCP tool load failed", { path: `mcp:${name}`, error: message });
1375
+ errors.set(name, this.#serverError(message));
1376
+ reportedErrors.add(name);
1377
+ logger.error("MCP tool load failed", { path: `mcp:${name}`, serverName: name, error: message });
1256
1378
  });
1257
1379
  }
1258
1380
 
@@ -1331,12 +1453,22 @@ export class MCPManager {
1331
1453
  if (!this.#toolsOnly && withinDeclaredConnectionWindow(task.config, startupElapsedMs)) {
1332
1454
  logger.warn("MCP server still connecting after the startup wait", {
1333
1455
  path: `mcp:${task.name}`,
1456
+ serverName: task.name,
1334
1457
  startupWaitMs: startupTimeoutMs,
1335
1458
  declaredTimeoutMs: task.config.timeout,
1336
1459
  });
1337
1460
  continue;
1338
1461
  }
1339
1462
  const message = `MCP server connection timed out during startup: ${task.name}`;
1463
+ if (!this.#toolsOnly) {
1464
+ logger.warn("MCP server connection timed out during startup", {
1465
+ path: `mcp:${task.name}`,
1466
+ serverName: task.name,
1467
+ startupWaitMs: startupTimeoutMs,
1468
+ declaredTimeoutMs: task.config.timeout,
1469
+ remediation: "Set a per-server timeout with `gjc mcp add --timeout <ms>` for slower servers.",
1470
+ });
1471
+ }
1340
1472
  errors.set(task.name, this.#serverError(message));
1341
1473
  reportedErrors.add(task.name);
1342
1474
  task.connectionAbort.abort(new Error(message));
@@ -1344,7 +1476,7 @@ export class MCPManager {
1344
1476
  if (this.#pendingToolLoads.get(task.name) === task.toolsPromise)
1345
1477
  this.#pendingToolLoads.delete(task.name);
1346
1478
  this.#pendingConnectionControllers.delete(task.name);
1347
- void this.#disconnectServer(task.name).catch(error => {
1479
+ void this.#disconnectServer(task.name, { preserveConfig: this.#toolsOnly }).catch(error => {
1348
1480
  this.#logLeaseReleaseFailure(task.name, undefined, error);
1349
1481
  });
1350
1482
  }
@@ -1368,26 +1500,39 @@ export class MCPManager {
1368
1500
  continue;
1369
1501
  }
1370
1502
  connectedServers.add(name);
1371
- const reconnect = () => this.reconnectServer(name);
1372
- try {
1373
- allTools.push(
1374
- ...MCPTool.fromTools(this.#connectionForLease(connection), serverTools, reconnect, {
1375
- noReplay: task.config.sharing === "shared",
1376
- inputHandler: () => this.#inputRequestHandler ?? undefined,
1377
- }),
1378
- );
1379
- } catch (error) {
1380
- await this.#cleanupConnectionTasks(connectionTasks);
1381
- throw error;
1503
+ if (this.#isExactToolPublicationAllowed(name)) {
1504
+ const reconnect = () => this.reconnectServer(name);
1505
+ try {
1506
+ allTools.push(
1507
+ ...MCPTool.fromTools(
1508
+ this.#connectionForLease(connection),
1509
+ serverTools,
1510
+ reconnect,
1511
+ this.#exactToolOptions(name, task.config.sharing === "shared"),
1512
+ ),
1513
+ );
1514
+ } catch (error) {
1515
+ await this.#cleanupConnectionTasks(connectionTasks);
1516
+ throw error;
1517
+ }
1382
1518
  }
1383
1519
  } else if (task.tracked.status === "rejected") {
1384
1520
  const reason = task.tracked.reason;
1385
1521
  this.#retainConnectionCleanupFailure(name, reason);
1386
1522
  const message = reason instanceof Error ? reason.message : String(reason);
1523
+ if (!(this.#toolsOnly && reason instanceof MCPExpectedFailure)) {
1524
+ logger.warn("MCP server connection failed during startup", {
1525
+ path: `mcp:${name}`,
1526
+ serverName: name,
1527
+ error: message,
1528
+ remediation:
1529
+ "Check the server command and set --timeout <ms> when startup is expected to be slow.",
1530
+ });
1531
+ }
1387
1532
  errors.set(name, this.#serverError(message));
1388
1533
  reportedErrors.add(name);
1389
1534
  if (this.#toolsOnly && reason instanceof MCPExpectedFailure) {
1390
- await this.#disconnectServer(name).catch(error => {
1535
+ await this.#disconnectServer(name, { preserveConfig: true }).catch(error => {
1391
1536
  this.#logLeaseReleaseFailure(name, this.#connections.get(name), error);
1392
1537
  });
1393
1538
  }
@@ -1396,7 +1541,7 @@ export class MCPManager {
1396
1541
  }
1397
1542
  } else {
1398
1543
  const cached = cachedTools.get(name);
1399
- if (cached) {
1544
+ if (cached && this.#isExactToolPublicationAllowed(name)) {
1400
1545
  const source = this.#sources.get(name);
1401
1546
  const reconnect = () => this.reconnectServer(name);
1402
1547
  try {
@@ -1407,10 +1552,7 @@ export class MCPManager {
1407
1552
  () => this.#waitForConnection(name).then(connection => this.#connectionForLease(connection)),
1408
1553
  source,
1409
1554
  reconnect,
1410
- {
1411
- noReplay: task.config.sharing === "shared",
1412
- inputHandler: () => this.#inputRequestHandler ?? undefined,
1413
- },
1555
+ this.#exactToolOptions(name, task.config.sharing === "shared"),
1414
1556
  ),
1415
1557
  );
1416
1558
  } catch (error) {
@@ -1431,7 +1573,7 @@ export class MCPManager {
1431
1573
  }
1432
1574
 
1433
1575
  // Update cached tools
1434
- if (shouldPublishToolSnapshot) this.#tools = allTools;
1576
+ if (shouldPublishToolSnapshot) this.#publishToolCatalog(allTools);
1435
1577
  allowBackgroundLogging = true;
1436
1578
 
1437
1579
  return {
@@ -1443,13 +1585,25 @@ export class MCPManager {
1443
1585
  }
1444
1586
 
1445
1587
  #replaceServerTools(name: string, tools: CustomTool<TSchema, MCPToolDetails>[]): void {
1446
- this.#tools = this.#tools.filter(
1588
+ if (!this.#isExactToolPublicationAllowed(name)) return;
1589
+ const publishedTools = this.#tools.filter(
1447
1590
  tool => !((tool instanceof MCPTool || tool instanceof DeferredMCPTool) && tool.mcpServerName === name),
1448
1591
  );
1449
- this.#tools.push(...tools);
1592
+ if (!this.#suppressedServers.has(name)) publishedTools.push(...tools);
1450
1593
  // Stable sort by name so reconnect order does not perturb the array.
1451
1594
  // See `sortMCPToolsByName` for the cache-stability rationale.
1452
- sortMCPToolsByName(this.#tools);
1595
+ sortMCPToolsByName(publishedTools);
1596
+ this.#publishToolCatalog(publishedTools);
1597
+ }
1598
+
1599
+ #exactToolOptions(
1600
+ name: string,
1601
+ noReplay: boolean,
1602
+ ): { noReplay: boolean; isAvailable?: () => boolean; inputHandler: () => MCPInputRequestHandler | undefined } {
1603
+ const inputHandler = () => this.#inputRequestHandler ?? undefined;
1604
+ return this.#toolsOnly
1605
+ ? { noReplay, isAvailable: () => !this.#suppressedServers.has(name), inputHandler }
1606
+ : { noReplay, inputHandler };
1453
1607
  }
1454
1608
 
1455
1609
  #triggerNotificationRefresh(serverName: string, kind: "tools" | "resources" | "prompts"): void {
@@ -1525,7 +1679,463 @@ export class MCPManager {
1525
1679
  * Get all loaded tools.
1526
1680
  */
1527
1681
  getTools(): CustomTool<TSchema, MCPToolDetails>[] {
1528
- return [...this.#tools];
1682
+ return this.#tools.filter(tool => !tool.mcpServerName || this.#isExactToolPublicationAllowed(tool.mcpServerName));
1683
+ }
1684
+
1685
+ /**
1686
+ * Read the fenced catalog and publication state atomically.
1687
+ *
1688
+ * An empty catalog is still authoritative after publication or while an
1689
+ * exact control is in flight. Deferred startup may fall back to its discovery
1690
+ * result only for the explicit `unpublished` state.
1691
+ */
1692
+ getToolCatalogSnapshot(): MCPToolCatalogSnapshot {
1693
+ const exactControlFence =
1694
+ this.#toolsOnly &&
1695
+ (this.#suppressedServers.size > 0 ||
1696
+ this.#pendingExactSuspensions.size > 0 ||
1697
+ this.#pendingExactControlServers.size > 0);
1698
+ return {
1699
+ tools: this.getTools(),
1700
+ publication: exactControlFence ? "fenced" : this.#toolCatalogPublished ? "published" : "unpublished",
1701
+ generation: this.#toolCatalogGeneration,
1702
+ };
1703
+ }
1704
+
1705
+ #publishToolCatalog(tools: CustomTool<TSchema, MCPToolDetails>[]): void {
1706
+ this.#tools = tools;
1707
+ this.#toolCatalogGeneration++;
1708
+ this.#toolCatalogPublished = true;
1709
+ }
1710
+
1711
+ #isExactToolPublicationAllowed(name: string): boolean {
1712
+ return (
1713
+ !this.#toolsOnly ||
1714
+ (!this.#suppressedServers.has(name) &&
1715
+ !this.#pendingExactSuspensions.has(name) &&
1716
+ !this.#pendingExactControlServers.has(name))
1717
+ );
1718
+ }
1719
+
1720
+ isExactServerSuppressed(name: string): boolean {
1721
+ this.#assertExactServerControl();
1722
+ return this.#suppressedServers.has(name);
1723
+ }
1724
+
1725
+ #exactServerToolCount(name: string): number {
1726
+ return this.#tools.reduce((count, tool) => (tool.mcpServerName === name ? count + 1 : count), 0);
1727
+ }
1728
+
1729
+ #assertExactServerControl(): void {
1730
+ if (!this.#toolsOnly) throw new Error("Exact MCP server controls require a tools-only manager");
1731
+ }
1732
+
1733
+ /**
1734
+ * Prepare one exact-config control without publishing manager state. Session
1735
+ * registry and prompt validation run against `tools`; commit is the single
1736
+ * publication point and abort releases only an unpublished candidate.
1737
+ */
1738
+ async prepareExactServerControl(
1739
+ action: "suspend" | "resume" | "reconnect",
1740
+ name: string,
1741
+ ): Promise<PreparedExactMcpServerControl> {
1742
+ this.#assertExactServerControl();
1743
+ if (!this.#serverConfigs.has(name) && !this.#connections.has(name)) {
1744
+ return this.#settledExactControl({ name, status: "unknown-server", toolCount: 0 });
1745
+ }
1746
+ if (action === "suspend") {
1747
+ if (this.#suppressedServers.has(name)) {
1748
+ return this.#settledExactControl({ name, status: "already-suspended", toolCount: 0 });
1749
+ }
1750
+ this.#pendingExactSuspensions.add(name);
1751
+ await this.#activeSharedRebinds.get(name)?.promise;
1752
+ const tools = this.#tools.filter(
1753
+ tool =>
1754
+ tool.mcpServerName !== name && (!tool.mcpServerName || !this.#suppressedServers.has(tool.mcpServerName)),
1755
+ );
1756
+ return {
1757
+ result: { name, status: "suspended", toolCount: 0 },
1758
+ tools,
1759
+ canCommit: () => true,
1760
+ commit: async () => {
1761
+ this.#suppressedServers.add(name);
1762
+ this.#pendingExactSuspensions.delete(name);
1763
+ this.#reconnectBackoffs.get(name)?.abort(new Error(`MCP server suspended: ${name}`));
1764
+ for (const tool of this.#tools) {
1765
+ if (tool.mcpServerName === name) (tool as MCPTool | DeferredMCPTool).invalidateForSessionControl();
1766
+ }
1767
+ await this.#activeSharedRebinds.get(name)?.promise;
1768
+ },
1769
+ abort: async () => {
1770
+ this.#pendingExactSuspensions.delete(name);
1771
+ },
1772
+ };
1773
+ }
1774
+ if (action === "resume" && !this.#suppressedServers.has(name)) {
1775
+ return this.#settledExactControl({
1776
+ name,
1777
+ status: "not-suspended",
1778
+ toolCount: this.#exactServerToolCount(name),
1779
+ });
1780
+ }
1781
+ if (action === "reconnect" && this.#suppressedServers.has(name)) {
1782
+ return this.#settledExactControl({ name, status: "unavailable", toolCount: 0 });
1783
+ }
1784
+ const automaticReconnect = this.#pendingReconnections.get(name);
1785
+ if (automaticReconnect) {
1786
+ this.#pendingExactControlServers.add(name);
1787
+ let connection: MCPServerConnection | null;
1788
+ try {
1789
+ connection = await automaticReconnect;
1790
+ } catch (error) {
1791
+ this.#pendingExactControlServers.delete(name);
1792
+ this.#drainDeferredSharedRebinds();
1793
+ throw error;
1794
+ }
1795
+ if (!connection) {
1796
+ this.#pendingExactControlServers.delete(name);
1797
+ this.#drainDeferredSharedRebinds();
1798
+ return this.#settledExactControl({ name, status: "unavailable", toolCount: 0 });
1799
+ }
1800
+ let candidateTools: CustomTool<TSchema, MCPToolDetails>[];
1801
+ try {
1802
+ candidateTools = await this.#buildExactServerTools(name, connection);
1803
+ } catch (error) {
1804
+ this.#pendingExactControlServers.delete(name);
1805
+ this.#drainDeferredSharedRebinds();
1806
+ throw error;
1807
+ }
1808
+ return this.#preparedCatalogCommit(
1809
+ name,
1810
+ action === "resume" ? "resumed" : "reconnected",
1811
+ candidateTools,
1812
+ undefined,
1813
+ connection,
1814
+ );
1815
+ }
1816
+ this.#pendingExactControlServers.add(name);
1817
+ const existing = this.#connections.get(name);
1818
+ if (action === "resume" && existing?.transport.connected) {
1819
+ try {
1820
+ const candidateTools = await this.#buildExactServerTools(name, existing);
1821
+ return this.#preparedCatalogCommit(name, "resumed", candidateTools, undefined, existing);
1822
+ } catch {
1823
+ // A mapped transport can close while suppressed; recover with an
1824
+ // unpublished physical candidate instead of exposing stale state.
1825
+ }
1826
+ }
1827
+ try {
1828
+ const candidate = await this.#prepareExactReplacement(name);
1829
+ return this.#preparedCatalogCommit(
1830
+ name,
1831
+ action === "resume" ? "resumed" : "reconnected",
1832
+ candidate.tools,
1833
+ candidate,
1834
+ undefined,
1835
+ );
1836
+ } catch (error) {
1837
+ const cleanupFailure = this.#retainConnectionCleanupFailure(name, error);
1838
+ if (cleanupFailure) {
1839
+ logger.error("MCP exact replacement cleanup failed", {
1840
+ path: `mcp:${name}`,
1841
+ error: cleanupFailure,
1842
+ });
1843
+ }
1844
+ this.#pendingExactControlServers.delete(name);
1845
+ this.#drainDeferredSharedRebinds();
1846
+ return this.#settledExactControl({ name, status: "unavailable", toolCount: 0 });
1847
+ }
1848
+ }
1849
+
1850
+ /** Clear all session-local suppression before this owner adopts a new identity. */
1851
+ async prepareExactServerControlReset(): Promise<PreparedExactMcpCatalog> {
1852
+ this.#assertExactServerControl();
1853
+ const prepared: PreparedExactMcpServerControl[] = [];
1854
+ for (const name of [...this.#suppressedServers]) {
1855
+ try {
1856
+ const candidate = await this.prepareExactServerControl("resume", name);
1857
+ if (candidate.result.status !== "resumed") {
1858
+ logger.warn("MCP server did not resume during identity reset", {
1859
+ path: `mcp:${name}`,
1860
+ status: candidate.result.status,
1861
+ });
1862
+ await candidate.abort();
1863
+ continue;
1864
+ }
1865
+ prepared.push(candidate);
1866
+ } catch (error) {
1867
+ // A suspended server's reachability must not block identity adoption.
1868
+ logger.warn("MCP server resume failed during identity reset", { path: `mcp:${name}`, error });
1869
+ }
1870
+ }
1871
+ const resumedNames = new Set(prepared.map(candidate => candidate.result.name));
1872
+ const carriedOver = this.#tools.filter(
1873
+ tool =>
1874
+ !tool.mcpServerName ||
1875
+ (!this.#suppressedServers.has(tool.mcpServerName) && !resumedNames.has(tool.mcpServerName)),
1876
+ );
1877
+ const resumedTools = prepared.flatMap(candidate =>
1878
+ candidate.tools.filter(tool => tool.mcpServerName === candidate.result.name),
1879
+ );
1880
+ const tools = [...carriedOver, ...resumedTools];
1881
+ sortMCPToolsByName(tools);
1882
+ return {
1883
+ tools,
1884
+ canCommit: () => prepared.every(candidate => candidate.canCommit()),
1885
+ commit: async () => {
1886
+ try {
1887
+ for (const candidate of prepared) {
1888
+ if (!candidate.precommit)
1889
+ throw new Error("Exact MCP reset candidate does not support atomic publication");
1890
+ candidate.precommit();
1891
+ }
1892
+ } catch (error) {
1893
+ await Promise.allSettled(prepared.map(candidate => candidate.abort()));
1894
+ throw error;
1895
+ }
1896
+ for (const candidate of prepared) {
1897
+ if (!candidate.publish) throw new Error("Exact MCP reset candidate does not support atomic publication");
1898
+ candidate.publish();
1899
+ }
1900
+ this.#publishToolCatalog(tools);
1901
+ this.#suppressedServers.clear();
1902
+ this.#pendingExactSuspensions.clear();
1903
+ this.#drainDeferredSharedRebinds();
1904
+ },
1905
+ abort: async () => {
1906
+ await Promise.allSettled(prepared.map(candidate => candidate.abort()));
1907
+ },
1908
+ };
1909
+ }
1910
+
1911
+ #settledExactControl(result: ExactMcpServerControlResult): PreparedExactMcpServerControl {
1912
+ return { result, tools: this.getTools(), canCommit: () => true, commit: async () => {}, abort: async () => {} };
1913
+ }
1914
+
1915
+ async #buildExactServerTools(
1916
+ name: string,
1917
+ connection: MCPServerConnection,
1918
+ ): Promise<CustomTool<TSchema, MCPToolDetails>[]> {
1919
+ const config = this.#serverConfigs.get(name) ?? connection.config;
1920
+ const serverTools = await listTools(this.#connectionForLease(connection));
1921
+ const reconnect = () => this.reconnectServer(name);
1922
+ return MCPTool.fromTools(
1923
+ this.#connectionForLease(connection),
1924
+ serverTools,
1925
+ reconnect,
1926
+ this.#exactToolOptions(name, config.sharing === "shared"),
1927
+ );
1928
+ }
1929
+
1930
+ async #preparedCatalogCommit(
1931
+ name: string,
1932
+ status: "resumed" | "reconnected",
1933
+ serverTools: CustomTool<TSchema, MCPToolDetails>[],
1934
+ candidate:
1935
+ | {
1936
+ connection: MCPServerConnection;
1937
+ lease: MCPPoolLease;
1938
+ canCommit(): boolean;
1939
+ publish(): void;
1940
+ abort(): Promise<void>;
1941
+ }
1942
+ | undefined,
1943
+ expectedConnection: MCPServerConnection | undefined,
1944
+ ): Promise<PreparedExactMcpServerControl> {
1945
+ const tools = [
1946
+ ...this.#tools.filter(
1947
+ tool =>
1948
+ tool.mcpServerName !== name && (!tool.mcpServerName || !this.#suppressedServers.has(tool.mcpServerName)),
1949
+ ),
1950
+ ...serverTools,
1951
+ ];
1952
+ sortMCPToolsByName(tools);
1953
+ if (this.#toolsOnly && new Set(tools.map(tool => tool.name)).size !== tools.length) {
1954
+ let abortError: unknown;
1955
+ try {
1956
+ await candidate?.abort();
1957
+ } catch (error) {
1958
+ abortError = error;
1959
+ }
1960
+ this.#pendingExactControlServers.delete(name);
1961
+ this.#drainDeferredSharedRebinds();
1962
+ if (abortError !== undefined) throw abortError;
1963
+ return this.#settledExactControl({ name, status: "unavailable", toolCount: 0 });
1964
+ }
1965
+ let settled = false;
1966
+ const precommit = (): void => {
1967
+ if (settled) return;
1968
+ if (
1969
+ candidate
1970
+ ? !candidate.canCommit()
1971
+ : expectedConnection &&
1972
+ (this.#connections.get(name) !== expectedConnection || !expectedConnection.transport.connected)
1973
+ ) {
1974
+ throw new Error(`MCP exact control predecessor changed before commit: ${name}`);
1975
+ }
1976
+ };
1977
+ const publish = (): void => {
1978
+ if (settled) return;
1979
+ candidate?.publish();
1980
+ settled = true;
1981
+ if (candidate) {
1982
+ this.#leaseByConnection.set(candidate.connection, candidate.lease);
1983
+ this.#connections.set(name, candidate.connection);
1984
+ this.#registerLease(name, candidate.connection);
1985
+ }
1986
+ for (const tool of this.#tools) {
1987
+ if (tool.mcpServerName === name) (tool as MCPTool | DeferredMCPTool).invalidateForSessionControl();
1988
+ }
1989
+ const publishedTools = [
1990
+ ...this.#tools.filter(
1991
+ tool =>
1992
+ tool.mcpServerName !== name &&
1993
+ (!tool.mcpServerName || !this.#suppressedServers.has(tool.mcpServerName)),
1994
+ ),
1995
+ ...serverTools,
1996
+ ];
1997
+ sortMCPToolsByName(publishedTools);
1998
+ this.#publishToolCatalog(publishedTools);
1999
+ this.#suppressedServers.delete(name);
2000
+ this.#pendingExactControlServers.delete(name);
2001
+ this.#drainDeferredSharedRebinds();
2002
+ };
2003
+ return {
2004
+ result: { name, status, toolCount: serverTools.length },
2005
+ tools,
2006
+ canCommit: () =>
2007
+ candidate
2008
+ ? candidate.canCommit()
2009
+ : !expectedConnection ||
2010
+ (this.#connections.get(name) === expectedConnection && expectedConnection.transport.connected),
2011
+ precommit,
2012
+ publish,
2013
+ commit: async () => {
2014
+ if (settled) return;
2015
+ try {
2016
+ precommit();
2017
+ publish();
2018
+ } catch (error) {
2019
+ let abortError: unknown;
2020
+ try {
2021
+ await candidate?.abort();
2022
+ } catch (cleanupError) {
2023
+ abortError = cleanupError;
2024
+ }
2025
+ this.#pendingExactControlServers.delete(name);
2026
+ this.#drainDeferredSharedRebinds();
2027
+ if (abortError !== undefined) {
2028
+ throw new AggregateError([error, abortError], `MCP exact control commit and cleanup failed: ${name}`);
2029
+ }
2030
+ throw error;
2031
+ }
2032
+ },
2033
+ abort: async () => {
2034
+ if (settled) return;
2035
+ let abortError: unknown;
2036
+ try {
2037
+ await candidate?.abort();
2038
+ } catch (cleanupError) {
2039
+ abortError = cleanupError;
2040
+ }
2041
+ settled = true;
2042
+ this.#pendingExactControlServers.delete(name);
2043
+ this.#drainDeferredSharedRebinds();
2044
+ if (abortError !== undefined) throw abortError;
2045
+ },
2046
+ };
2047
+ }
2048
+
2049
+ async #prepareExactReplacement(name: string): Promise<{
2050
+ connection: MCPServerConnection;
2051
+ lease: MCPPoolLease;
2052
+ tools: CustomTool<TSchema, MCPToolDetails>[];
2053
+ canCommit(): boolean;
2054
+ publish(): void;
2055
+ abort(): Promise<void>;
2056
+ }> {
2057
+ const config = this.#serverConfigs.get(name);
2058
+ if (!config) throw new Error(`MCP server unavailable: ${name}`);
2059
+ await this.#closePendingConnectionCleanup(name);
2060
+ const resolved = await this.#resolveAuthConfig(config);
2061
+ const abort = new AbortController();
2062
+ this.#pendingConnectionControllers.set(name, abort);
2063
+ let prepared:
2064
+ | {
2065
+ lease: MCPPoolLease;
2066
+ canCommit(): boolean;
2067
+ publish(): void;
2068
+ abort(): Promise<void>;
2069
+ }
2070
+ | undefined;
2071
+ const abortPrepared = async (): Promise<void> => {
2072
+ if (!prepared) return;
2073
+ try {
2074
+ await prepared.abort();
2075
+ } catch (error) {
2076
+ const cleanupFailure = this.#retainConnectionCleanupFailure(name, error);
2077
+ if (cleanupFailure) {
2078
+ logger.error("MCP exact replacement abort cleanup failed", {
2079
+ path: `mcp:${name}`,
2080
+ error: cleanupFailure,
2081
+ });
2082
+ }
2083
+ throw error;
2084
+ }
2085
+ };
2086
+ try {
2087
+ prepared = await this.#pool.prepareReplacement(name, resolved, {
2088
+ keyConfig: config,
2089
+ sharingMode:
2090
+ config.sharing === "shared" &&
2091
+ (resolved.type === "http" || resolved.type === "sse" || resolved.type === "stdio")
2092
+ ? "shared"
2093
+ : "per-session",
2094
+ sessionId: config.sharing === "shared" ? undefined : this.#sessionId,
2095
+ signal: abort.signal,
2096
+ advertiseRoots: false,
2097
+ effectiveCwd: resolved.type === "stdio" ? (resolved.cwd ?? this.cwd) : this.cwd,
2098
+ capabilityProfile: "tools-only",
2099
+ effectiveHeaders: resolved.type === "http" || resolved.type === "sse" ? resolved.headers : undefined,
2100
+ onRequest: (method, params) => this.#handleServerRequest(method, params),
2101
+ onCleanupPending: error => this.#retainPendingAcquireCleanup(name, error),
2102
+ });
2103
+ const connection = prepared.lease.connection;
2104
+ connection.config = config;
2105
+ const source = this.#sources.get(name) ?? this.#connections.get(name)?._source;
2106
+ if (source) connection._source = source;
2107
+ const definitions = await listTools(prepared.lease.connectionForLease());
2108
+ const reconnect = () => this.reconnectServer(name);
2109
+ const tools = MCPTool.fromTools(
2110
+ prepared.lease.connectionForLease(),
2111
+ definitions,
2112
+ reconnect,
2113
+ this.#exactToolOptions(name, config.sharing === "shared"),
2114
+ );
2115
+ return {
2116
+ connection,
2117
+ lease: prepared.lease,
2118
+ tools,
2119
+ canCommit: prepared.canCommit,
2120
+ publish: prepared.publish,
2121
+ abort: abortPrepared,
2122
+ };
2123
+ } catch (error) {
2124
+ this.#retainConnectionCleanupFailure(name, error);
2125
+ try {
2126
+ await abortPrepared();
2127
+ } catch (abortError) {
2128
+ throw new AggregateError(
2129
+ [error, abortError],
2130
+ `MCP exact replacement preparation and cleanup failed: ${name}`,
2131
+ );
2132
+ }
2133
+ throw error;
2134
+ } finally {
2135
+ if (this.#pendingConnectionControllers.get(name) === abort) {
2136
+ this.#pendingConnectionControllers.delete(name);
2137
+ }
2138
+ }
1529
2139
  }
1530
2140
 
1531
2141
  /**
@@ -1776,7 +2386,7 @@ export class MCPManager {
1776
2386
  await this.#disconnectServer(name);
1777
2387
  }
1778
2388
 
1779
- async #disconnectServer(name: string): Promise<void> {
2389
+ async #disconnectServer(name: string, options: { preserveConfig?: boolean } = {}): Promise<void> {
1780
2390
  const nextEpoch = (this.#disconnectEpochs.get(name) ?? 0) + 1;
1781
2391
  this.#disconnectEpochs.set(name, nextEpoch);
1782
2392
  this.#pendingConnectionControllers.get(name)?.abort(new Error(`MCP server disconnected: ${name}`));
@@ -1787,7 +2397,7 @@ export class MCPManager {
1787
2397
  this.#pendingToolLoads.delete(name);
1788
2398
  this.#pendingReconnections.delete(name);
1789
2399
  this.#sources.delete(name);
1790
- this.#serverConfigs.delete(name);
2400
+ if (!options.preserveConfig) this.#serverConfigs.delete(name);
1791
2401
  this.#pendingResourceRefresh.delete(name);
1792
2402
  const connection = this.#connections.get(name);
1793
2403
 
@@ -1820,10 +2430,15 @@ export class MCPManager {
1820
2430
  const hadTools = this.#tools.some(
1821
2431
  tool => (tool instanceof MCPTool || tool instanceof DeferredMCPTool) && tool.mcpServerName === name,
1822
2432
  );
1823
- this.#tools = this.#tools.filter(
2433
+ const remainingTools = this.#tools.filter(
1824
2434
  tool => !((tool instanceof MCPTool || tool instanceof DeferredMCPTool) && tool.mcpServerName === name),
1825
2435
  );
1826
- if (hadTools) this.#onToolsChanged?.(this.#tools);
2436
+ if (hadTools) {
2437
+ this.#publishToolCatalog(remainingTools);
2438
+ this.#onToolsChanged?.(this.#tools);
2439
+ } else {
2440
+ this.#tools = remainingTools;
2441
+ }
1827
2442
 
1828
2443
  // Notify prompt consumers so stale commands are cleared
1829
2444
  if (connection?.prompts?.length) this.#onPromptsChanged?.(name);
@@ -1926,8 +2541,11 @@ export class MCPManager {
1926
2541
  this.#pendingResourceRefresh.clear();
1927
2542
  this.#sources.clear();
1928
2543
  this.#serverConfigs.clear();
2544
+ this.#suppressedServers.clear();
2545
+ this.#pendingExactSuspensions.clear();
2546
+ this.#pendingExactControlServers.clear();
1929
2547
  this.#connections.clear();
1930
- this.#tools = [];
2548
+ this.#publishToolCatalog([]);
1931
2549
  this.#subscribedResources.clear();
1932
2550
  const releaseFailures = [
1933
2551
  ...scopedReleaseFailures,
@@ -1966,6 +2584,8 @@ export class MCPManager {
1966
2584
  async reconnectServer(name: string): Promise<MCPServerConnection | null> {
1967
2585
  if (this.#connectionSetSealed) return null;
1968
2586
  if (this.#scopedLifecycle === "disconnecting") return null;
2587
+ if (this.#pendingExactControlServers.has(name)) return this.#connections.get(name) ?? null;
2588
+ if (this.#suppressedServers.has(name)) return null;
1969
2589
  const pending = this.#pendingReconnections.get(name);
1970
2590
  if (pending) return pending;
1971
2591
 
@@ -2163,6 +2783,9 @@ export class MCPManager {
2163
2783
  // while we were connecting (e.g. /mcp reload called disconnectAll).
2164
2784
  if (
2165
2785
  !this.#serverConfigs.has(name) ||
2786
+ this.#suppressedServers.has(name) ||
2787
+ this.#pendingExactSuspensions.has(name) ||
2788
+ this.#pendingExactControlServers.has(name) ||
2166
2789
  this.#epoch !== globalEpoch ||
2167
2790
  (this.#disconnectEpochs.get(name) ?? 0) !== disconnectEpoch ||
2168
2791
  (lifecycleEpoch !== undefined &&
@@ -2193,16 +2816,25 @@ export class MCPManager {
2193
2816
  }
2194
2817
  try {
2195
2818
  const serverTools = await listTools(this.#connectionForLease(connection));
2196
- if (!this.#isCurrentConnection(name, config, globalEpoch, disconnectEpoch, connection)) {
2819
+ // An exact control can claim this server while tools load; publishing here
2820
+ // would install a catalog the control never validated.
2821
+ if (
2822
+ !this.#isCurrentConnection(name, config, globalEpoch, disconnectEpoch, connection) ||
2823
+ this.#suppressedServers.has(name) ||
2824
+ this.#pendingExactSuspensions.has(name) ||
2825
+ this.#pendingExactControlServers.has(name)
2826
+ ) {
2197
2827
  const disconnectError = new Error(`Server "${name}" was disconnected during tool loading`);
2198
2828
  await this.#releaseLeasePreservingPrimary(name, connection);
2199
2829
  throw disconnectError;
2200
2830
  }
2201
2831
  const reconnect = () => this.reconnectServer(name);
2202
- const customTools = MCPTool.fromTools(this.#connectionForLease(connection), serverTools, reconnect, {
2203
- noReplay: config.sharing === "shared",
2204
- inputHandler: () => this.#inputRequestHandler ?? undefined,
2205
- });
2832
+ const customTools = MCPTool.fromTools(
2833
+ this.#connectionForLease(connection),
2834
+ serverTools,
2835
+ reconnect,
2836
+ this.#exactToolOptions(name, config.sharing === "shared"),
2837
+ );
2206
2838
  void this.toolCache?.set(name, config, serverTools);
2207
2839
  this.#replaceServerTools(name, customTools);
2208
2840
  this.#onToolsChanged?.(this.#tools);
@@ -2267,10 +2899,12 @@ export class MCPManager {
2267
2899
  const serverTools = await listTools(facade);
2268
2900
  if (!this.#isCurrentConnection(name, connection.config, globalEpoch, disconnectEpoch, connection)) return;
2269
2901
  const reconnect = () => this.reconnectServer(name);
2270
- const customTools = MCPTool.fromTools(facade, serverTools, reconnect, {
2271
- noReplay: connection.config.sharing === "shared",
2272
- inputHandler: () => this.#inputRequestHandler ?? undefined,
2273
- });
2902
+ const customTools = MCPTool.fromTools(
2903
+ facade,
2904
+ serverTools,
2905
+ reconnect,
2906
+ this.#exactToolOptions(name, connection.config.sharing === "shared"),
2907
+ );
2274
2908
  void this.toolCache?.set(name, connection.config, serverTools);
2275
2909
 
2276
2910
  // Replace tools from this server