@copilotkit/aimock 1.43.0 → 1.45.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 (396) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/CHANGELOG.md +46 -0
  4. package/README.md +14 -2
  5. package/dist/agui-handler.d.ts.map +1 -1
  6. package/dist/aimock-cli.cjs +31 -5
  7. package/dist/aimock-cli.cjs.map +1 -1
  8. package/dist/aimock-cli.d.cts.map +1 -1
  9. package/dist/aimock-cli.d.ts.map +1 -1
  10. package/dist/aimock-cli.js +31 -5
  11. package/dist/aimock-cli.js.map +1 -1
  12. package/dist/bedrock-converse.cjs +344 -43
  13. package/dist/bedrock-converse.cjs.map +1 -1
  14. package/dist/bedrock-converse.d.cts.map +1 -1
  15. package/dist/bedrock-converse.d.ts.map +1 -1
  16. package/dist/bedrock-converse.js +345 -44
  17. package/dist/bedrock-converse.js.map +1 -1
  18. package/dist/bedrock.cjs +195 -42
  19. package/dist/bedrock.cjs.map +1 -1
  20. package/dist/bedrock.d.cts.map +1 -1
  21. package/dist/bedrock.d.ts.map +1 -1
  22. package/dist/bedrock.js +196 -43
  23. package/dist/bedrock.js.map +1 -1
  24. package/dist/chaos.cjs +9 -5
  25. package/dist/chaos.cjs.map +1 -1
  26. package/dist/chaos.d.cts.map +1 -1
  27. package/dist/chaos.d.ts.map +1 -1
  28. package/dist/chaos.js +10 -7
  29. package/dist/chaos.js.map +1 -1
  30. package/dist/cli.cjs +238 -9
  31. package/dist/cli.cjs.map +1 -1
  32. package/dist/cli.js +242 -13
  33. package/dist/cli.js.map +1 -1
  34. package/dist/cohere.cjs +159 -72
  35. package/dist/cohere.cjs.map +1 -1
  36. package/dist/cohere.d.cts.map +1 -1
  37. package/dist/cohere.d.ts.map +1 -1
  38. package/dist/cohere.js +160 -73
  39. package/dist/cohere.js.map +1 -1
  40. package/dist/config-loader.cjs +63 -5
  41. package/dist/config-loader.cjs.map +1 -1
  42. package/dist/config-loader.d.cts +37 -4
  43. package/dist/config-loader.d.cts.map +1 -1
  44. package/dist/config-loader.d.ts +37 -4
  45. package/dist/config-loader.d.ts.map +1 -1
  46. package/dist/config-loader.js +63 -5
  47. package/dist/config-loader.js.map +1 -1
  48. package/dist/constants.cjs +8 -0
  49. package/dist/constants.cjs.map +1 -1
  50. package/dist/constants.d.cts +6 -2
  51. package/dist/constants.d.ts +6 -2
  52. package/dist/constants.js +8 -1
  53. package/dist/constants.js.map +1 -1
  54. package/dist/echo-text.cjs +65 -0
  55. package/dist/echo-text.cjs.map +1 -0
  56. package/dist/echo-text.d.cts +22 -0
  57. package/dist/echo-text.d.cts.map +1 -0
  58. package/dist/echo-text.d.ts +22 -0
  59. package/dist/echo-text.d.ts.map +1 -0
  60. package/dist/echo-text.js +65 -0
  61. package/dist/echo-text.js.map +1 -0
  62. package/dist/embeddings.cjs +18 -1
  63. package/dist/embeddings.cjs.map +1 -1
  64. package/dist/embeddings.d.cts +1 -1
  65. package/dist/embeddings.d.cts.map +1 -1
  66. package/dist/embeddings.d.ts +1 -1
  67. package/dist/embeddings.d.ts.map +1 -1
  68. package/dist/embeddings.js +18 -1
  69. package/dist/embeddings.js.map +1 -1
  70. package/dist/fakes-plugin.cjs +131 -0
  71. package/dist/fakes-plugin.cjs.map +1 -0
  72. package/dist/fakes-plugin.d.cts +23 -0
  73. package/dist/fakes-plugin.d.cts.map +1 -0
  74. package/dist/fakes-plugin.d.ts +23 -0
  75. package/dist/fakes-plugin.d.ts.map +1 -0
  76. package/dist/fakes-plugin.js +127 -0
  77. package/dist/fakes-plugin.js.map +1 -0
  78. package/dist/files.cjs +9 -11
  79. package/dist/files.cjs.map +1 -1
  80. package/dist/files.d.cts.map +1 -1
  81. package/dist/files.d.ts.map +1 -1
  82. package/dist/files.js +10 -13
  83. package/dist/files.js.map +1 -1
  84. package/dist/fine-tuning.cjs +1 -19
  85. package/dist/fine-tuning.cjs.map +1 -1
  86. package/dist/fine-tuning.d.cts.map +1 -1
  87. package/dist/fine-tuning.d.ts.map +1 -1
  88. package/dist/fine-tuning.js +2 -20
  89. package/dist/fine-tuning.js.map +1 -1
  90. package/dist/fixture-loader-services.cjs +116 -0
  91. package/dist/fixture-loader-services.cjs.map +1 -0
  92. package/dist/fixture-loader-services.d.cts +48 -0
  93. package/dist/fixture-loader-services.d.cts.map +1 -0
  94. package/dist/fixture-loader-services.d.ts +48 -0
  95. package/dist/fixture-loader-services.d.ts.map +1 -0
  96. package/dist/fixture-loader-services.js +114 -0
  97. package/dist/fixture-loader-services.js.map +1 -0
  98. package/dist/fixture-loader.cjs +552 -29
  99. package/dist/fixture-loader.cjs.map +1 -1
  100. package/dist/fixture-loader.d.cts +140 -2
  101. package/dist/fixture-loader.d.cts.map +1 -1
  102. package/dist/fixture-loader.d.ts +140 -2
  103. package/dist/fixture-loader.d.ts.map +1 -1
  104. package/dist/fixture-loader.js +542 -31
  105. package/dist/fixture-loader.js.map +1 -1
  106. package/dist/gemini-embeddings.cjs +42 -2
  107. package/dist/gemini-embeddings.cjs.map +1 -1
  108. package/dist/gemini-embeddings.js +43 -3
  109. package/dist/gemini-embeddings.js.map +1 -1
  110. package/dist/gemini-interactions.cjs +288 -52
  111. package/dist/gemini-interactions.cjs.map +1 -1
  112. package/dist/gemini-interactions.d.cts.map +1 -1
  113. package/dist/gemini-interactions.d.ts.map +1 -1
  114. package/dist/gemini-interactions.js +289 -53
  115. package/dist/gemini-interactions.js.map +1 -1
  116. package/dist/gemini.cjs +234 -38
  117. package/dist/gemini.cjs.map +1 -1
  118. package/dist/gemini.d.cts.map +1 -1
  119. package/dist/gemini.d.ts.map +1 -1
  120. package/dist/gemini.js +235 -39
  121. package/dist/gemini.js.map +1 -1
  122. package/dist/helpers.cjs +1157 -12
  123. package/dist/helpers.cjs.map +1 -1
  124. package/dist/helpers.d.cts +85 -4
  125. package/dist/helpers.d.cts.map +1 -1
  126. package/dist/helpers.d.ts +85 -4
  127. package/dist/helpers.d.ts.map +1 -1
  128. package/dist/helpers.js +1113 -14
  129. package/dist/helpers.js.map +1 -1
  130. package/dist/images.cjs +3 -2
  131. package/dist/images.cjs.map +1 -1
  132. package/dist/images.js +3 -2
  133. package/dist/images.js.map +1 -1
  134. package/dist/index.cjs +39 -1
  135. package/dist/index.d.cts +11 -4
  136. package/dist/index.d.ts +11 -4
  137. package/dist/index.js +11 -4
  138. package/dist/jest.cjs +43 -14
  139. package/dist/jest.cjs.map +1 -1
  140. package/dist/jest.d.cts +47 -5
  141. package/dist/jest.d.cts.map +1 -1
  142. package/dist/jest.d.ts +47 -5
  143. package/dist/jest.d.ts.map +1 -1
  144. package/dist/jest.js +45 -16
  145. package/dist/jest.js.map +1 -1
  146. package/dist/journal.cjs +155 -13
  147. package/dist/journal.cjs.map +1 -1
  148. package/dist/journal.d.cts +54 -4
  149. package/dist/journal.d.cts.map +1 -1
  150. package/dist/journal.d.ts +54 -4
  151. package/dist/journal.d.ts.map +1 -1
  152. package/dist/journal.js +155 -13
  153. package/dist/journal.js.map +1 -1
  154. package/dist/live-sanitize.cjs +4 -32
  155. package/dist/live-sanitize.cjs.map +1 -1
  156. package/dist/live-sanitize.js +4 -32
  157. package/dist/live-sanitize.js.map +1 -1
  158. package/dist/llmock.cjs +204 -39
  159. package/dist/llmock.cjs.map +1 -1
  160. package/dist/llmock.d.cts +51 -1
  161. package/dist/llmock.d.cts.map +1 -1
  162. package/dist/llmock.d.ts +51 -1
  163. package/dist/llmock.d.ts.map +1 -1
  164. package/dist/llmock.js +206 -41
  165. package/dist/llmock.js.map +1 -1
  166. package/dist/mcp-fakes-mount.cjs +217 -0
  167. package/dist/mcp-fakes-mount.cjs.map +1 -0
  168. package/dist/mcp-fakes-mount.js +211 -0
  169. package/dist/mcp-fakes-mount.js.map +1 -0
  170. package/dist/mcp-fakes-report.cjs +111 -0
  171. package/dist/mcp-fakes-report.cjs.map +1 -0
  172. package/dist/mcp-fakes-report.d.cts +40 -0
  173. package/dist/mcp-fakes-report.d.cts.map +1 -0
  174. package/dist/mcp-fakes-report.d.ts +40 -0
  175. package/dist/mcp-fakes-report.d.ts.map +1 -0
  176. package/dist/mcp-fakes-report.js +107 -0
  177. package/dist/mcp-fakes-report.js.map +1 -0
  178. package/dist/mcp-fakes.cjs +1942 -0
  179. package/dist/mcp-fakes.cjs.map +1 -0
  180. package/dist/mcp-fakes.d.cts +504 -0
  181. package/dist/mcp-fakes.d.cts.map +1 -0
  182. package/dist/mcp-fakes.d.ts +504 -0
  183. package/dist/mcp-fakes.d.ts.map +1 -0
  184. package/dist/mcp-fakes.js +1937 -0
  185. package/dist/mcp-fakes.js.map +1 -0
  186. package/dist/mcp-handler.cjs +534 -27
  187. package/dist/mcp-handler.cjs.map +1 -1
  188. package/dist/mcp-handler.d.cts +49 -0
  189. package/dist/mcp-handler.d.cts.map +1 -0
  190. package/dist/mcp-handler.d.ts +49 -0
  191. package/dist/mcp-handler.d.ts.map +1 -0
  192. package/dist/mcp-handler.js +530 -28
  193. package/dist/mcp-handler.js.map +1 -1
  194. package/dist/mcp-mock.cjs +326 -47
  195. package/dist/mcp-mock.cjs.map +1 -1
  196. package/dist/mcp-mock.d.cts +97 -1
  197. package/dist/mcp-mock.d.cts.map +1 -1
  198. package/dist/mcp-mock.d.ts +97 -1
  199. package/dist/mcp-mock.d.ts.map +1 -1
  200. package/dist/mcp-mock.js +327 -48
  201. package/dist/mcp-mock.js.map +1 -1
  202. package/dist/mcp-recorder.cjs +1224 -0
  203. package/dist/mcp-recorder.cjs.map +1 -0
  204. package/dist/mcp-recorder.d.cts +108 -0
  205. package/dist/mcp-recorder.d.cts.map +1 -0
  206. package/dist/mcp-recorder.d.ts +108 -0
  207. package/dist/mcp-recorder.d.ts.map +1 -0
  208. package/dist/mcp-recorder.js +1215 -0
  209. package/dist/mcp-recorder.js.map +1 -0
  210. package/dist/mcp-stub.cjs +5 -1
  211. package/dist/mcp-stub.d.cts +3 -1
  212. package/dist/mcp-stub.d.ts +3 -1
  213. package/dist/mcp-stub.js +3 -1
  214. package/dist/mcp-types.d.cts +6 -0
  215. package/dist/mcp-types.d.ts +6 -0
  216. package/dist/message-text.cjs +192 -0
  217. package/dist/message-text.cjs.map +1 -0
  218. package/dist/message-text.d.cts +31 -0
  219. package/dist/message-text.d.cts.map +1 -0
  220. package/dist/message-text.d.ts +31 -0
  221. package/dist/message-text.d.ts.map +1 -0
  222. package/dist/message-text.js +184 -0
  223. package/dist/message-text.js.map +1 -0
  224. package/dist/messages.cjs +400 -56
  225. package/dist/messages.cjs.map +1 -1
  226. package/dist/messages.d.cts.map +1 -1
  227. package/dist/messages.d.ts.map +1 -1
  228. package/dist/messages.js +401 -58
  229. package/dist/messages.js.map +1 -1
  230. package/dist/metrics.cjs +46 -66
  231. package/dist/metrics.cjs.map +1 -1
  232. package/dist/metrics.d.cts +14 -6
  233. package/dist/metrics.d.cts.map +1 -1
  234. package/dist/metrics.d.ts +14 -6
  235. package/dist/metrics.d.ts.map +1 -1
  236. package/dist/metrics.js +32 -40
  237. package/dist/metrics.js.map +1 -1
  238. package/dist/misbehavior.cjs +1523 -0
  239. package/dist/misbehavior.cjs.map +1 -0
  240. package/dist/misbehavior.d.cts +43 -0
  241. package/dist/misbehavior.d.cts.map +1 -0
  242. package/dist/misbehavior.d.ts +43 -0
  243. package/dist/misbehavior.d.ts.map +1 -0
  244. package/dist/misbehavior.js +1511 -0
  245. package/dist/misbehavior.js.map +1 -0
  246. package/dist/ollama.cjs +315 -113
  247. package/dist/ollama.cjs.map +1 -1
  248. package/dist/ollama.d.cts.map +1 -1
  249. package/dist/ollama.d.ts.map +1 -1
  250. package/dist/ollama.js +316 -114
  251. package/dist/ollama.js.map +1 -1
  252. package/dist/openapi.cjs +3405 -0
  253. package/dist/openapi.cjs.map +1 -0
  254. package/dist/openapi.d.cts +30 -0
  255. package/dist/openapi.d.cts.map +1 -0
  256. package/dist/openapi.d.ts +30 -0
  257. package/dist/openapi.d.ts.map +1 -0
  258. package/dist/openapi.js +3404 -0
  259. package/dist/openapi.js.map +1 -0
  260. package/dist/openrouter-video.cjs +4 -4
  261. package/dist/openrouter-video.cjs.map +1 -1
  262. package/dist/openrouter-video.d.cts.map +1 -1
  263. package/dist/openrouter-video.d.ts.map +1 -1
  264. package/dist/openrouter-video.js +4 -4
  265. package/dist/openrouter-video.js.map +1 -1
  266. package/dist/record-sanitize.cjs +231 -0
  267. package/dist/record-sanitize.cjs.map +1 -0
  268. package/dist/record-sanitize.js +224 -0
  269. package/dist/record-sanitize.js.map +1 -0
  270. package/dist/recorder.cjs +115 -6
  271. package/dist/recorder.cjs.map +1 -1
  272. package/dist/recorder.d.cts +2 -1
  273. package/dist/recorder.d.cts.map +1 -1
  274. package/dist/recorder.d.ts +2 -1
  275. package/dist/recorder.d.ts.map +1 -1
  276. package/dist/recorder.js +116 -8
  277. package/dist/recorder.js.map +1 -1
  278. package/dist/responses.cjs +701 -166
  279. package/dist/responses.cjs.map +1 -1
  280. package/dist/responses.d.cts +5 -13
  281. package/dist/responses.d.cts.map +1 -1
  282. package/dist/responses.d.ts +5 -13
  283. package/dist/responses.d.ts.map +1 -1
  284. package/dist/responses.js +699 -169
  285. package/dist/responses.js.map +1 -1
  286. package/dist/route-registry.cjs +951 -0
  287. package/dist/route-registry.cjs.map +1 -0
  288. package/dist/route-registry.d.cts +33 -0
  289. package/dist/route-registry.d.cts.map +1 -0
  290. package/dist/route-registry.d.ts +33 -0
  291. package/dist/route-registry.d.ts.map +1 -0
  292. package/dist/route-registry.js +866 -0
  293. package/dist/route-registry.js.map +1 -0
  294. package/dist/router.cjs +24 -2
  295. package/dist/router.cjs.map +1 -1
  296. package/dist/router.d.cts.map +1 -1
  297. package/dist/router.d.ts.map +1 -1
  298. package/dist/router.js +25 -4
  299. package/dist/router.js.map +1 -1
  300. package/dist/server.cjs +1159 -264
  301. package/dist/server.cjs.map +1 -1
  302. package/dist/server.d.cts +4 -1
  303. package/dist/server.d.cts.map +1 -1
  304. package/dist/server.d.ts +4 -1
  305. package/dist/server.d.ts.map +1 -1
  306. package/dist/server.js +1067 -172
  307. package/dist/server.js.map +1 -1
  308. package/dist/speech.cjs +4 -2
  309. package/dist/speech.cjs.map +1 -1
  310. package/dist/speech.js +4 -2
  311. package/dist/speech.js.map +1 -1
  312. package/dist/stream-collapse.cjs +236 -34
  313. package/dist/stream-collapse.cjs.map +1 -1
  314. package/dist/stream-collapse.d.cts +39 -4
  315. package/dist/stream-collapse.d.cts.map +1 -1
  316. package/dist/stream-collapse.d.ts +39 -4
  317. package/dist/stream-collapse.d.ts.map +1 -1
  318. package/dist/stream-collapse.js +235 -35
  319. package/dist/stream-collapse.js.map +1 -1
  320. package/dist/suite.cjs +1 -1
  321. package/dist/suite.js +1 -1
  322. package/dist/transcription.cjs +2 -2
  323. package/dist/transcription.cjs.map +1 -1
  324. package/dist/transcription.d.cts.map +1 -1
  325. package/dist/transcription.d.ts.map +1 -1
  326. package/dist/transcription.js +2 -2
  327. package/dist/transcription.js.map +1 -1
  328. package/dist/types.cjs +18 -0
  329. package/dist/types.cjs.map +1 -0
  330. package/dist/types.d.cts +516 -5
  331. package/dist/types.d.cts.map +1 -1
  332. package/dist/types.d.ts +516 -5
  333. package/dist/types.d.ts.map +1 -1
  334. package/dist/types.js +17 -0
  335. package/dist/types.js.map +1 -0
  336. package/dist/validate-cli.cjs +123 -33
  337. package/dist/validate-cli.cjs.map +1 -1
  338. package/dist/validate-cli.js +125 -35
  339. package/dist/validate-cli.js.map +1 -1
  340. package/dist/vector-stores.cjs +1180 -0
  341. package/dist/vector-stores.cjs.map +1 -0
  342. package/dist/vector-stores.d.cts +106 -0
  343. package/dist/vector-stores.d.cts.map +1 -0
  344. package/dist/vector-stores.d.ts +106 -0
  345. package/dist/vector-stores.d.ts.map +1 -0
  346. package/dist/vector-stores.js +1164 -0
  347. package/dist/vector-stores.js.map +1 -0
  348. package/dist/vector-types.d.cts.map +1 -1
  349. package/dist/version.cjs +45 -0
  350. package/dist/version.cjs.map +1 -0
  351. package/dist/version.js +44 -0
  352. package/dist/version.js.map +1 -0
  353. package/dist/video.cjs +19 -0
  354. package/dist/video.cjs.map +1 -1
  355. package/dist/video.d.cts.map +1 -1
  356. package/dist/video.d.ts.map +1 -1
  357. package/dist/video.js +19 -0
  358. package/dist/video.js.map +1 -1
  359. package/dist/vitest.cjs +77 -16
  360. package/dist/vitest.cjs.map +1 -1
  361. package/dist/vitest.d.cts +38 -5
  362. package/dist/vitest.d.cts.map +1 -1
  363. package/dist/vitest.d.ts +38 -5
  364. package/dist/vitest.d.ts.map +1 -1
  365. package/dist/vitest.js +78 -17
  366. package/dist/vitest.js.map +1 -1
  367. package/dist/watcher.cjs +6 -2
  368. package/dist/watcher.cjs.map +1 -1
  369. package/dist/watcher.js +6 -2
  370. package/dist/watcher.js.map +1 -1
  371. package/dist/ws-gemini-live.cjs +210 -101
  372. package/dist/ws-gemini-live.cjs.map +1 -1
  373. package/dist/ws-gemini-live.d.cts +9 -3
  374. package/dist/ws-gemini-live.d.cts.map +1 -1
  375. package/dist/ws-gemini-live.d.ts +9 -3
  376. package/dist/ws-gemini-live.d.ts.map +1 -1
  377. package/dist/ws-gemini-live.js +211 -102
  378. package/dist/ws-gemini-live.js.map +1 -1
  379. package/dist/ws-realtime.cjs +175 -62
  380. package/dist/ws-realtime.cjs.map +1 -1
  381. package/dist/ws-realtime.d.cts +8 -3
  382. package/dist/ws-realtime.d.cts.map +1 -1
  383. package/dist/ws-realtime.d.ts +8 -3
  384. package/dist/ws-realtime.d.ts.map +1 -1
  385. package/dist/ws-realtime.js +176 -63
  386. package/dist/ws-realtime.js.map +1 -1
  387. package/dist/ws-responses.cjs +121 -16
  388. package/dist/ws-responses.cjs.map +1 -1
  389. package/dist/ws-responses.d.cts +8 -12
  390. package/dist/ws-responses.d.cts.map +1 -1
  391. package/dist/ws-responses.d.ts +8 -12
  392. package/dist/ws-responses.d.ts.map +1 -1
  393. package/dist/ws-responses.js +123 -18
  394. package/dist/ws-responses.js.map +1 -1
  395. package/package.json +13 -2
  396. package/skills/write-fixtures/SKILL.md +179 -21
@@ -1,8 +1,47 @@
1
1
  const require_runtime = require('./_virtual/_rolldown/runtime.cjs');
2
+ const require_message_text = require('./message-text.cjs');
3
+ const require_helpers = require('./helpers.cjs');
2
4
  const require_jsonrpc = require('./jsonrpc.cjs');
5
+ const require_types = require('./types.cjs');
3
6
  let node_crypto = require("node:crypto");
4
7
 
5
8
  //#region src/mcp-handler.ts
9
+ /**
10
+ * `data.aimock.code` of a `tools/call` whose fake claim threw: an aimock
11
+ * defect (a validated entry whose result could not be built or sent), not a
12
+ * scenario failure. Answered with the JSON-RPC internal-error code `-32603`;
13
+ * the entry stays unconsumed.
14
+ */
15
+ const MCP_FAKE_INTERNAL_ERROR = "MCP_FAKE_INTERNAL_ERROR";
16
+ const MCP_FAKE_INTERNAL_ERROR_RPC_CODE = -32603;
17
+ /** An empty record, for the caller to pass in and read even if the handler throws. */
18
+ function newMCPRequestRecord() {
19
+ return {
20
+ identity: null,
21
+ messages: []
22
+ };
23
+ }
24
+ /**
25
+ * C8: the `onToolCall` handlers that answer a config `mcp.tools[].result`.
26
+ * `tools/call` reports such an answer as `answeredBy: "config"`. Internal:
27
+ * not exported from the package.
28
+ */
29
+ const configToolHandlers = /* @__PURE__ */ new WeakSet();
30
+ /** C7: the syslog levels of `logging/setLevel`, lowest first. */
31
+ const LOG_LEVELS = [
32
+ "debug",
33
+ "info",
34
+ "notice",
35
+ "warning",
36
+ "error",
37
+ "critical",
38
+ "alert",
39
+ "emergency"
40
+ ];
41
+ /** C7: the rank of a syslog level name, or -1 when it is not one. */
42
+ function logLevelRank(level) {
43
+ return typeof level === "string" ? LOG_LEVELS.indexOf(level) : -1;
44
+ }
6
45
  function jsonRpcResult(id, result) {
7
46
  return {
8
47
  jsonrpc: "2.0",
@@ -10,26 +49,195 @@ function jsonRpcResult(id, result) {
10
49
  result
11
50
  };
12
51
  }
13
- function jsonRpcError(id, code, message) {
52
+ function jsonRpcError(id, code, message, data) {
14
53
  return {
15
54
  jsonrpc: "2.0",
16
55
  id,
17
- error: {
56
+ error: data === void 0 ? {
18
57
  code,
19
58
  message
59
+ } : {
60
+ code,
61
+ message,
62
+ data
20
63
  }
21
64
  };
22
65
  }
66
+ /**
67
+ * The identity part of a fake message or log line (I9): `testId "<id>"`,
68
+ * `context "<ctx>"`, both, or `no testId or context`.
69
+ */
70
+ function describeMcpIdentity(identity) {
71
+ const { testId, context } = identity;
72
+ if (testId !== null && context !== null) return require_message_text.msg`testId ${require_message_text.quote(testId)}, context ${require_message_text.quote(context)}`;
73
+ if (testId !== null) return require_message_text.msg`testId ${require_message_text.quote(testId)}`;
74
+ if (context !== null) return require_message_text.msg`context ${require_message_text.quote(context)}`;
75
+ return require_message_text.msg`no testId or context`;
76
+ }
77
+ /** A value as JSON text for a message part. */
78
+ function jsonPart(value) {
79
+ return require_message_text.jsonText(JSON.stringify(value) ?? "null");
80
+ }
81
+ /**
82
+ * The 9.2 error for a failed claim (`mismatch`, `exhausted`, `evicted`), or
83
+ * for an undeclared tool under `deny` (`not_declared`).
84
+ */
85
+ function fakeFailure(claim, tool, ctx, declaredTools) {
86
+ const who = describeMcpIdentity(ctx.identity);
87
+ const base = {
88
+ tool,
89
+ testId: ctx.identity.testId,
90
+ context: ctx.identity.context,
91
+ mount: ctx.mount
92
+ };
93
+ switch (claim.kind) {
94
+ case "mismatch": {
95
+ const list = claim.declared.map((d) => d.args !== void 0 ? require_message_text.msg`${require_message_text.plainText(d.id)} ${jsonPart(d.args)}` : require_message_text.msg`${require_message_text.plainText(d.id)} anyArgs`).reduce((acc, part, i) => i === 0 ? part : require_message_text.msg`${acc}; ${part}`, require_message_text.msg`none`);
96
+ return {
97
+ code: "MCP_FAKE_MISMATCH",
98
+ outcome: "mismatch",
99
+ message: require_message_text.build(require_message_text.msg`aimock MCP fake mismatch: tool ${require_message_text.quote(tool)} was called with arguments that match no declared fake (${who}). Received ${jsonPart(claim.received)}. Declared: ${list}.`),
100
+ aimock: {
101
+ code: "MCP_FAKE_MISMATCH",
102
+ ...base,
103
+ received: claim.received,
104
+ declared: claim.declared,
105
+ firstDifference: claim.firstDifference
106
+ }
107
+ };
108
+ }
109
+ case "exhausted": {
110
+ const used = claim.matchingDeclared === 1 ? require_message_text.msg`the 1 matching fake is` : require_message_text.msg`all ${claim.matchingDeclared} matching fakes are`;
111
+ return {
112
+ code: "MCP_FAKE_EXHAUSTED",
113
+ outcome: "exhausted",
114
+ message: require_message_text.build(require_message_text.msg`aimock MCP fake exhausted: tool ${require_message_text.quote(tool)} with ${jsonPart(claim.received)} was called again, but ${used} already used (${who}).`),
115
+ aimock: {
116
+ code: "MCP_FAKE_EXHAUSTED",
117
+ ...base,
118
+ received: claim.received,
119
+ matchingDeclared: claim.matchingDeclared,
120
+ matchingConsumed: claim.matchingConsumed,
121
+ matchingIds: claim.matchingIds
122
+ }
123
+ };
124
+ }
125
+ case "evicted": return {
126
+ code: "MCP_FAKE_EVICTED",
127
+ outcome: "evicted",
128
+ evicted: {
129
+ testId: claim.testId,
130
+ cap: claim.maxTestIds
131
+ },
132
+ message: require_message_text.build(require_message_text.msg`aimock MCP fake evicted: consumption state for testId ${require_message_text.quote(claim.testId)} was evicted by the per-mount test-id cap (${claim.maxTestIds}); reset before reusing this test id (${who}).`),
133
+ aimock: {
134
+ code: "MCP_FAKE_EVICTED",
135
+ ...base,
136
+ testId: claim.testId,
137
+ cap: claim.maxTestIds
138
+ }
139
+ };
140
+ case "not_declared": return {
141
+ code: "MCP_FAKE_NOT_DECLARED",
142
+ outcome: "not_declared",
143
+ message: require_message_text.build(require_message_text.msg`Unknown tool: ${require_message_text.plainText(tool)} (aimock MCP fake not declared: this scenario denies undeclared tools; ${who}).`),
144
+ aimock: {
145
+ code: "MCP_FAKE_NOT_DECLARED",
146
+ ...base,
147
+ declaredTools: declaredTools()
148
+ }
149
+ };
150
+ }
151
+ }
23
152
  function createMCPRequestHandler(state) {
153
+ /** Per-request fake context, set by the outer handler for the dispatcher's methods. */
154
+ const contexts = /* @__PURE__ */ new WeakMap();
155
+ /** C7: each session's `logging/setLevel` level; dropped on DELETE. */
156
+ const logLevels = /* @__PURE__ */ new Map();
157
+ /** The initialize capabilities: `logging` only on a mount with recorded logs (C7). */
158
+ const capabilities = () => state.fakes.hasRecordedLogs() ? {
159
+ tools: {},
160
+ resources: {},
161
+ prompts: {},
162
+ logging: {}
163
+ } : {
164
+ tools: {},
165
+ resources: {},
166
+ prompts: {}
167
+ };
168
+ /**
169
+ * Spec 10 steps 1-2 for `tools/call`: a fake answer or fake failure, or
170
+ * `null` to fall through to today's behavior (step 3).
171
+ */
172
+ const callFake = (ctx, outcome, tool, args, id) => {
173
+ const event = {
174
+ identity: ctx.identity,
175
+ tool,
176
+ mount: ctx.mount,
177
+ args
178
+ };
179
+ let claim;
180
+ try {
181
+ claim = state.fakes.claim(tool, args, ctx.identity);
182
+ } catch (err) {
183
+ const thrown = err instanceof Error ? err.message : String(err);
184
+ const message = require_message_text.build(require_message_text.msg`aimock MCP fake internal error: tool ${require_message_text.quote(tool)} could not be answered (${describeMcpIdentity(ctx.identity)}): ${require_message_text.plainText(thrown)}`);
185
+ outcome.error = message;
186
+ state.onFakeEvent({
187
+ ...event,
188
+ kind: "internal_error",
189
+ code: MCP_FAKE_INTERNAL_ERROR,
190
+ message
191
+ });
192
+ return jsonRpcError(id, MCP_FAKE_INTERNAL_ERROR_RPC_CODE, message, { aimock: {
193
+ code: MCP_FAKE_INTERNAL_ERROR,
194
+ tool,
195
+ testId: ctx.identity.testId,
196
+ context: ctx.identity.context,
197
+ mount: ctx.mount,
198
+ error: thrown
199
+ } });
200
+ }
201
+ if (claim.kind === "answer") {
202
+ outcome.mcpFake = {
203
+ id: claim.entry.id,
204
+ outcome: "answered"
205
+ };
206
+ state.onFakeEvent({
207
+ ...event,
208
+ kind: "answered",
209
+ entryId: claim.entry.id
210
+ });
211
+ return jsonRpcResult(id, claim.result);
212
+ }
213
+ let failure;
214
+ if (claim.kind === "none") {
215
+ if (state.fakes.policy(ctx.identity) !== "deny") return null;
216
+ failure = fakeFailure({ kind: "not_declared" }, tool, ctx, () => state.fakes.declaredTools(ctx.identity));
217
+ } else failure = fakeFailure(claim, tool, ctx, () => []);
218
+ outcome.mcpFake = {
219
+ id: null,
220
+ outcome: failure.outcome
221
+ };
222
+ state.onFakeEvent(failure.outcome === "evicted" ? {
223
+ ...event,
224
+ kind: "evicted",
225
+ code: failure.code,
226
+ message: failure.message,
227
+ ...failure.evicted
228
+ } : {
229
+ ...event,
230
+ kind: failure.outcome,
231
+ code: failure.code,
232
+ message: failure.message
233
+ });
234
+ return jsonRpcError(id, require_types.MCP_FAKE_ERROR_CODES[failure.code], failure.message, { aimock: failure.aimock });
235
+ };
24
236
  const dispatcher = require_jsonrpc.createJsonRpcDispatcher({ methods: {
25
237
  initialize: async (_params, id) => {
26
238
  return jsonRpcResult(id, {
27
239
  protocolVersion: "2025-03-26",
28
- capabilities: {
29
- tools: {},
30
- resources: {},
31
- prompts: {}
32
- },
240
+ capabilities: capabilities(),
33
241
  serverInfo: state.serverInfo
34
242
  });
35
243
  },
@@ -42,15 +250,68 @@ function createMCPRequestHandler(state) {
42
250
  ping: async (_params, id) => {
43
251
  return jsonRpcResult(id, {});
44
252
  },
45
- "tools/list": async (_params, id) => {
253
+ "logging/setLevel": async (params, id, req) => {
254
+ if (!state.fakes.hasRecordedLogs()) return jsonRpcError(id, -32601, "Method not found");
255
+ const level = params ?? {};
256
+ if (logLevelRank(level.level) === -1) return jsonRpcError(id, -32602, "Invalid log level");
257
+ const sessionId = req.headers["mcp-session-id"];
258
+ if (typeof sessionId === "string") logLevels.set(sessionId, String(level.level));
259
+ return jsonRpcResult(id, {});
260
+ },
261
+ "tools/list": async (_params, id, req) => {
46
262
  const tools = [];
47
263
  for (const { def } of state.tools.values()) tools.push(def);
264
+ const ctx = contexts.get(req);
265
+ const recorded = ctx ? state.fakes.recordedList(ctx.identity) : null;
266
+ if (ctx && recorded) {
267
+ const listed = [...recorded];
268
+ const names = new Set(recorded.map((t) => t.name));
269
+ for (const def of tools) if (!names.has(def.name)) {
270
+ names.add(def.name);
271
+ listed.push(def);
272
+ }
273
+ for (const fake of state.fakes.listTools(ctx.identity)) if (!names.has(fake.name)) {
274
+ names.add(fake.name);
275
+ listed.push(fake);
276
+ }
277
+ return jsonRpcResult(id, { tools: listed });
278
+ }
279
+ if (ctx) {
280
+ const registered = new Set(tools.map((t) => t.name));
281
+ for (const fake of state.fakes.listTools(ctx.identity)) if (!registered.has(fake.name)) tools.push(fake);
282
+ }
48
283
  return jsonRpcResult(id, { tools });
49
284
  },
50
- "tools/call": async (params, id) => {
51
- const { name, arguments: args } = params ?? {};
52
- if (!name) return jsonRpcError(id, -32602, "Missing tool name");
285
+ "tools/call": async (params, id, req) => {
286
+ const ctx = contexts.get(req);
287
+ const precomputed = ctx?.precomputed;
288
+ if (ctx) ctx.precomputed = void 0;
289
+ const isNotification = !precomputed && ctx?.notifications[ctx.calls.length] === true;
290
+ if (!precomputed) ctx?.calls.push({
291
+ mcpFake: null,
292
+ error: null
293
+ });
294
+ const outcome = ctx?.calls[ctx.calls.length - 1] ?? {
295
+ mcpFake: null,
296
+ error: null
297
+ };
298
+ const { name: rawName, arguments: args } = params ?? {};
299
+ if (!rawName) return jsonRpcError(id, -32602, "Missing tool name");
300
+ if (typeof rawName !== "string") return jsonRpcError(id, -32602, require_message_text.build(require_message_text.msg`Invalid tool name: expected a string, got ${require_message_text.fixed(Array.isArray(rawName) ? "array" : typeof rawName)}`));
301
+ const name = rawName;
302
+ if (precomputed?.kind === "reply") return precomputed.value;
303
+ if (ctx && !isNotification && !precomputed) {
304
+ const fake = callFake(ctx, outcome, name, args, id);
305
+ if (fake) return fake;
306
+ }
53
307
  const entry = state.tools.get(name);
308
+ if (ctx && !isNotification) state.onUnfaked({
309
+ identity: ctx.identity,
310
+ tool: name,
311
+ mount: ctx.mount,
312
+ args,
313
+ answeredBy: !entry ? "unknown-tool" : entry.handler && configToolHandlers.has(entry.handler) ? "config" : entry.handler ? "handler" : "empty"
314
+ });
54
315
  if (!entry) return jsonRpcError(id, -32602, `Unknown tool: ${name}`);
55
316
  if (entry.handler) try {
56
317
  const result = await entry.handler(args);
@@ -110,50 +371,126 @@ function createMCPRequestHandler(state) {
110
371
  return jsonRpcResult(id, { messages: [] });
111
372
  }
112
373
  } });
113
- return async (req, res, body) => {
374
+ /** Answer a rejected identity (H4, H5) with HTTP 400, in the session-error shape. */
375
+ const rejectIdentity = (res, resolution) => {
376
+ res.writeHead(resolution.error.status, { "Content-Type": "application/json" });
377
+ res.end(JSON.stringify({
378
+ error: resolution.error.message,
379
+ code: resolution.error.code
380
+ }));
381
+ };
382
+ /**
383
+ * L2: report each identity value that fell back to the raw value (H1),
384
+ * naming its source (header or query) and the value itself, and any query
385
+ * name that did not decode. `fellBack` says only that some value of the
386
+ * field fell back; the header is checked on its own, and the query by the
387
+ * same resolver given the query alone, so the rules are the resolver's.
388
+ */
389
+ const reportFallback = (sessionId, req, resolution) => {
390
+ if (!state.hasFakes()) return;
391
+ const { fellBack } = resolution;
392
+ if (fellBack.testId || fellBack.context) {
393
+ const queryOnly = require_helpers.resolveMcpIdentity({
394
+ headers: {},
395
+ url: req.url
396
+ });
397
+ for (const field of ["testId", "context"]) {
398
+ if (!fellBack[field]) continue;
399
+ const header = req.headers[IDENTITY_HEADERS[field]];
400
+ const headerSent = typeof header === "string" && header !== "";
401
+ if (headerSent && require_helpers.decodeMcpHeaderValue(header).fellBack) state.onDecodeFallback(sessionId, {
402
+ kind: "value",
403
+ field,
404
+ source: "header",
405
+ raw: header,
406
+ used: true
407
+ });
408
+ const fromQuery = queryOnly.ok && queryOnly.fellBack[field] ? queryOnly.identity[field] : null;
409
+ if (fromQuery !== null) state.onDecodeFallback(sessionId, {
410
+ kind: "value",
411
+ field,
412
+ source: "query",
413
+ raw: fromQuery,
414
+ used: !headerSent
415
+ });
416
+ }
417
+ }
418
+ if (resolution.undecodedQueryNames) state.onDecodeFallback(sessionId, {
419
+ kind: "names",
420
+ count: resolution.undecodedQueryNames
421
+ });
422
+ };
423
+ /**
424
+ * Handle one MCP request. `mount` is the path the mount is served at (I9;
425
+ * `/` for a standalone server). Resolves with what the request resolved,
426
+ * for the mount's journal entry.
427
+ */
428
+ return async (req, res, body, mount = "/", record = newMCPRequestRecord()) => {
429
+ /** T1: recorded `atMs` / `durationMs` are measured from here. */
430
+ const arrivedAt = performance.now();
114
431
  if (req.method === "DELETE") {
115
432
  const sessionId = req.headers["mcp-session-id"];
116
433
  if (!sessionId) {
117
434
  res.writeHead(400, { "Content-Type": "application/json" });
118
435
  res.end(JSON.stringify({ error: "Missing mcp-session-id header" }));
119
- return;
436
+ return record;
120
437
  }
121
438
  if (!state.sessions.has(sessionId)) {
122
439
  res.writeHead(404, { "Content-Type": "application/json" });
123
440
  res.end(JSON.stringify({ error: "Session not found" }));
124
- return;
441
+ return record;
125
442
  }
443
+ const resolution = require_helpers.resolveMcpIdentity(req, state.sessions.get(sessionId));
444
+ if (resolution.ok) record.identity = resolution.identity;
126
445
  state.sessions.delete(sessionId);
446
+ logLevels.delete(sessionId);
447
+ state.onSessionClosed(sessionId);
127
448
  res.writeHead(200, { "Content-Type": "application/json" });
128
449
  res.end(JSON.stringify({ ok: true }));
129
- return;
450
+ return record;
130
451
  }
452
+ const headerSessionId = req.headers["mcp-session-id"];
453
+ const knownSession = headerSessionId ? state.sessions.get(headerSessionId) : void 0;
131
454
  let parsed;
132
455
  try {
133
456
  parsed = JSON.parse(body);
134
457
  } catch {
458
+ const resolution = require_helpers.resolveMcpIdentity(req, knownSession);
459
+ if (!resolution.ok) {
460
+ rejectIdentity(res, resolution);
461
+ return record;
462
+ }
463
+ record.identity = resolution.identity;
464
+ if (headerSessionId && knownSession) reportFallback(headerSessionId, req, resolution);
135
465
  await dispatcher(req, res, body);
136
- return;
466
+ return record;
137
467
  }
138
468
  const method = typeof parsed === "object" && parsed !== null && "method" in parsed ? parsed.method : void 0;
139
469
  if (method === "initialize") {
140
470
  const id = typeof parsed === "object" && parsed !== null && "id" in parsed ? parsed.id : null;
471
+ const resolution = require_helpers.resolveMcpIdentity(req);
472
+ if (!resolution.ok) {
473
+ rejectIdentity(res, resolution);
474
+ return record;
475
+ }
476
+ record.identity = resolution.identity;
477
+ const { identity, supplied } = resolution;
141
478
  const sessionId = (0, node_crypto.randomUUID)();
142
479
  state.sessions.set(sessionId, {
143
480
  id: sessionId,
144
481
  initialized: false,
145
- createdAt: Date.now()
482
+ createdAt: Date.now(),
483
+ ...supplied.testId && identity.testId !== null ? { testId: identity.testId } : {},
484
+ ...supplied.context && identity.context !== null ? { context: identity.context } : {},
485
+ ...supplied.undeclared && identity.undeclared !== null ? { undeclared: identity.undeclared } : {}
146
486
  });
487
+ reportFallback(sessionId, req, resolution);
147
488
  const response = {
148
489
  jsonrpc: "2.0",
149
490
  id,
150
491
  result: {
151
492
  protocolVersion: "2025-03-26",
152
- capabilities: {
153
- tools: {},
154
- resources: {},
155
- prompts: {}
156
- },
493
+ capabilities: capabilities(),
157
494
  serverInfo: state.serverInfo
158
495
  }
159
496
  };
@@ -162,28 +499,198 @@ function createMCPRequestHandler(state) {
162
499
  "Mcp-Session-Id": sessionId
163
500
  });
164
501
  res.end(JSON.stringify(response));
165
- return;
502
+ return record;
503
+ }
504
+ const resolution = require_helpers.resolveMcpIdentity(req, knownSession);
505
+ if (!resolution.ok) {
506
+ rejectIdentity(res, resolution);
507
+ return record;
166
508
  }
167
- const sessionId = req.headers["mcp-session-id"];
509
+ record.identity = resolution.identity;
510
+ const sessionId = headerSessionId;
168
511
  if (!sessionId) {
169
512
  res.writeHead(400, { "Content-Type": "application/json" });
170
513
  res.end(JSON.stringify({ error: "Missing mcp-session-id header" }));
171
- return;
514
+ return record;
172
515
  }
173
516
  if (!state.sessions.has(sessionId)) {
174
517
  res.writeHead(404, { "Content-Type": "application/json" });
175
518
  res.end(JSON.stringify({ error: "Session not found" }));
176
- return;
519
+ return record;
177
520
  }
521
+ reportFallback(sessionId, req, resolution);
178
522
  if (!state.sessions.get(sessionId).initialized && method !== "notifications/initialized") {
179
523
  res.writeHead(400, { "Content-Type": "application/json" });
180
524
  res.end(JSON.stringify(jsonRpcError(typeof parsed === "object" && parsed !== null && "id" in parsed ? parsed.id : null, -32002, "Session not initialized")));
181
- return;
525
+ return record;
526
+ }
527
+ const notifications = (Array.isArray(parsed) ? parsed : [parsed]).filter((m) => isToolsCall(m) && m.jsonrpc === "2.0").map((m) => !("id" in m));
528
+ const ctx = {
529
+ identity: resolution.identity,
530
+ mount,
531
+ notifications,
532
+ calls: []
533
+ };
534
+ contexts.set(req, ctx);
535
+ const single = singleToolsCall(parsed);
536
+ if (single) {
537
+ const outcome = {
538
+ mcpFake: null,
539
+ error: null
540
+ };
541
+ ctx.calls.push(outcome);
542
+ const fake = callFake(ctx, outcome, single.name, single.args, single.id);
543
+ const replay = fake && outcome.mcpFake?.outcome === "answered" && outcome.mcpFake.id !== null ? state.fakes.replayOf(outcome.mcpFake.id) : null;
544
+ if (fake && "result" in fake && replay && (replay.notifications.length > 0 || replay.timing === "recorded" && replay.durationMs !== void 0)) {
545
+ await writeFakeToolAnswer(req, res, single.id, fake.result, replay, single.params, state.replaySpeed(), logLevels.get(sessionId) ?? null, arrivedAt);
546
+ record.messages = [{
547
+ body: single.message,
548
+ mcpFake: outcome.mcpFake,
549
+ error: outcome.error
550
+ }];
551
+ return record;
552
+ }
553
+ ctx.precomputed = fake ? {
554
+ kind: "reply",
555
+ value: fake
556
+ } : { kind: "none" };
182
557
  }
183
558
  await dispatcher(req, res, body);
559
+ let next = 0;
560
+ const messageOf = (message) => {
561
+ if (!isToolsCall(message)) return {
562
+ body: null,
563
+ mcpFake: null,
564
+ error: null
565
+ };
566
+ const outcome = message.jsonrpc === "2.0" ? ctx.calls[next++] : void 0;
567
+ return {
568
+ body: message,
569
+ mcpFake: outcome?.mcpFake ?? null,
570
+ error: outcome?.error ?? null
571
+ };
572
+ };
573
+ record.messages = Array.isArray(parsed) ? parsed.map(messageOf) : [messageOf(parsed)];
574
+ return record;
575
+ };
576
+ }
577
+ /**
578
+ * A single JSON-RPC `tools/call` request (not a batch, not a notification)
579
+ * with a string or number id and a string tool name, else `null`. Only such
580
+ * a message is claimed by the outer handler (MR15).
581
+ */
582
+ function singleToolsCall(parsed) {
583
+ if (!isToolsCall(parsed) || parsed.jsonrpc !== "2.0" || !("id" in parsed)) return null;
584
+ const id = parsed.id;
585
+ if (typeof id !== "string" && typeof id !== "number") return null;
586
+ const params = parsed.params;
587
+ if (typeof params !== "object" || params === null) return null;
588
+ const name = params.name;
589
+ if (typeof name !== "string" || name === "") return null;
590
+ return {
591
+ message: parsed,
592
+ id,
593
+ name,
594
+ args: params.arguments,
595
+ params
596
+ };
597
+ }
598
+ /** Resolve after `ms` (no wait when `ms <= 0`). */
599
+ function sleep(ms) {
600
+ return ms > 0 ? new Promise((resolve) => setTimeout(resolve, ms)) : Promise.resolve();
601
+ }
602
+ /** The client's `_meta.progressToken` of a request's params, else `undefined`. */
603
+ function progressTokenOf(params) {
604
+ if (typeof params !== "object" || params === null) return void 0;
605
+ const meta = params._meta;
606
+ if (typeof meta !== "object" || meta === null) return void 0;
607
+ const token = meta.progressToken;
608
+ return typeof token === "string" || typeof token === "number" ? token : void 0;
609
+ }
610
+ /**
611
+ * FA3 gate of one recorded notification for this request: the params to send,
612
+ * or `null` when it does not replay. `notifications/progress` replays only
613
+ * when the request carries a progress token, which replaces the recorded one;
614
+ * `notifications/message` only when the session set a log level (C7) and the
615
+ * line is at or above it. No other method replays.
616
+ */
617
+ function replayedParams(notification, progressToken, logLevel) {
618
+ if (notification.method === "notifications/progress") return progressToken === void 0 ? null : {
619
+ ...notification.params,
620
+ progressToken
184
621
  };
622
+ if (notification.method === "notifications/message") {
623
+ const min = logLevelRank(logLevel);
624
+ const rank = logLevelRank(notification.params.level);
625
+ return min !== -1 && rank >= min ? { ...notification.params } : null;
626
+ }
627
+ return null;
628
+ }
629
+ /**
630
+ * Write a fake's tools/call answer. SSE iff the entry has a notification whose
631
+ * FA3 gate passes AND Accept lists text/event-stream; else JSON. Timing per T1
632
+ * (value / speed) unless the block's timing is "immediate". `logLevel` is the
633
+ * session's `logging/setLevel` level (C7), `arrivedAt` the `performance.now()`
634
+ * of the request's arrival, which `atMs` and `durationMs` are measured from.
635
+ */
636
+ async function writeFakeToolAnswer(req, res, id, result, replay, params, speed, logLevel = null, arrivedAt = performance.now()) {
637
+ const timed = replay !== null && replay.timing === "recorded";
638
+ const waitUntil = (atMs) => timed ? sleep(atMs / speed - (performance.now() - arrivedAt)) : Promise.resolve();
639
+ const token = progressTokenOf(params);
640
+ const notifications = [...replay?.notifications ?? []].sort((a, b) => a.atMs - b.atMs).flatMap((n) => {
641
+ const sent = replayedParams(n, token, logLevel);
642
+ return sent ? [{
643
+ atMs: n.atMs,
644
+ method: n.method,
645
+ params: sent
646
+ }] : [];
647
+ });
648
+ const accept = req.headers.accept ?? "";
649
+ const answer = {
650
+ jsonrpc: "2.0",
651
+ id,
652
+ result
653
+ };
654
+ if (notifications.length > 0 && accept.includes("text/event-stream")) {
655
+ res.writeHead(200, {
656
+ "Content-Type": "text/event-stream",
657
+ "Cache-Control": "no-cache"
658
+ });
659
+ res.flushHeaders();
660
+ for (const n of notifications) {
661
+ await waitUntil(n.atMs);
662
+ if (res.destroyed) return;
663
+ res.write(`event: message\ndata: ${JSON.stringify({
664
+ jsonrpc: "2.0",
665
+ method: n.method,
666
+ params: n.params
667
+ })}\n\n`);
668
+ }
669
+ if (replay?.durationMs !== void 0) await waitUntil(replay.durationMs);
670
+ if (res.destroyed) return;
671
+ res.end(`event: message\ndata: ${JSON.stringify(answer)}\n\n`);
672
+ return;
673
+ }
674
+ if (replay?.durationMs !== void 0) await waitUntil(replay.durationMs);
675
+ if (res.destroyed) return;
676
+ res.writeHead(200, { "Content-Type": "application/json" });
677
+ res.end(JSON.stringify(answer));
678
+ }
679
+ /** The identity header of each field whose value can fall back (H1). */
680
+ const IDENTITY_HEADERS = {
681
+ testId: "x-test-id",
682
+ context: "x-aimock-context"
683
+ };
684
+ /** A JSON-RPC message object whose method is `tools/call`. */
685
+ function isToolsCall(message) {
686
+ return typeof message === "object" && message !== null && !Array.isArray(message) && "method" in message && message.method === "tools/call";
185
687
  }
186
688
 
187
689
  //#endregion
690
+ exports.configToolHandlers = configToolHandlers;
188
691
  exports.createMCPRequestHandler = createMCPRequestHandler;
692
+ exports.describeMcpIdentity = describeMcpIdentity;
693
+ exports.fakeFailure = fakeFailure;
694
+ exports.newMCPRequestRecord = newMCPRequestRecord;
695
+ exports.writeFakeToolAnswer = writeFakeToolAnswer;
189
696
  //# sourceMappingURL=mcp-handler.cjs.map