@copilotkit/aimock 1.7.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 (368) hide show
  1. package/.claude-plugin/marketplace.json +17 -0
  2. package/.claude-plugin/plugin.json +12 -0
  3. package/LICENSE +21 -0
  4. package/README.md +82 -0
  5. package/dist/_virtual/_rolldown/runtime.cjs +29 -0
  6. package/dist/a2a-handler.cjs +203 -0
  7. package/dist/a2a-handler.cjs.map +1 -0
  8. package/dist/a2a-handler.js +199 -0
  9. package/dist/a2a-handler.js.map +1 -0
  10. package/dist/a2a-mock.cjs +292 -0
  11. package/dist/a2a-mock.cjs.map +1 -0
  12. package/dist/a2a-mock.d.cts +41 -0
  13. package/dist/a2a-mock.d.cts.map +1 -0
  14. package/dist/a2a-mock.d.ts +41 -0
  15. package/dist/a2a-mock.d.ts.map +1 -0
  16. package/dist/a2a-mock.js +290 -0
  17. package/dist/a2a-mock.js.map +1 -0
  18. package/dist/a2a-stub.cjs +4 -0
  19. package/dist/a2a-stub.d.cts +3 -0
  20. package/dist/a2a-stub.d.ts +3 -0
  21. package/dist/a2a-stub.js +3 -0
  22. package/dist/a2a-types.d.cts +68 -0
  23. package/dist/a2a-types.d.cts.map +1 -0
  24. package/dist/a2a-types.d.ts +68 -0
  25. package/dist/a2a-types.d.ts.map +1 -0
  26. package/dist/aimock-cli.cjs +112 -0
  27. package/dist/aimock-cli.cjs.map +1 -0
  28. package/dist/aimock-cli.d.cts +19 -0
  29. package/dist/aimock-cli.d.cts.map +1 -0
  30. package/dist/aimock-cli.d.ts +19 -0
  31. package/dist/aimock-cli.d.ts.map +1 -0
  32. package/dist/aimock-cli.js +110 -0
  33. package/dist/aimock-cli.js.map +1 -0
  34. package/dist/aws-event-stream.cjs +117 -0
  35. package/dist/aws-event-stream.cjs.map +1 -0
  36. package/dist/aws-event-stream.d.cts +38 -0
  37. package/dist/aws-event-stream.d.cts.map +1 -0
  38. package/dist/aws-event-stream.d.ts +38 -0
  39. package/dist/aws-event-stream.d.ts.map +1 -0
  40. package/dist/aws-event-stream.js +114 -0
  41. package/dist/aws-event-stream.js.map +1 -0
  42. package/dist/bedrock-converse.cjs +445 -0
  43. package/dist/bedrock-converse.cjs.map +1 -0
  44. package/dist/bedrock-converse.d.cts +50 -0
  45. package/dist/bedrock-converse.d.cts.map +1 -0
  46. package/dist/bedrock-converse.d.ts +50 -0
  47. package/dist/bedrock-converse.d.ts.map +1 -0
  48. package/dist/bedrock-converse.js +443 -0
  49. package/dist/bedrock-converse.js.map +1 -0
  50. package/dist/bedrock.cjs +557 -0
  51. package/dist/bedrock.cjs.map +1 -0
  52. package/dist/bedrock.d.cts +41 -0
  53. package/dist/bedrock.d.cts.map +1 -0
  54. package/dist/bedrock.d.ts +41 -0
  55. package/dist/bedrock.d.ts.map +1 -0
  56. package/dist/bedrock.js +553 -0
  57. package/dist/bedrock.js.map +1 -0
  58. package/dist/chaos.cjs +114 -0
  59. package/dist/chaos.cjs.map +1 -0
  60. package/dist/chaos.d.cts +27 -0
  61. package/dist/chaos.d.cts.map +1 -0
  62. package/dist/chaos.d.ts +27 -0
  63. package/dist/chaos.d.ts.map +1 -0
  64. package/dist/chaos.js +113 -0
  65. package/dist/chaos.js.map +1 -0
  66. package/dist/cli.cjs +268 -0
  67. package/dist/cli.cjs.map +1 -0
  68. package/dist/cli.d.cts +1 -0
  69. package/dist/cli.d.ts +1 -0
  70. package/dist/cli.js +268 -0
  71. package/dist/cli.js.map +1 -0
  72. package/dist/cohere.cjs +434 -0
  73. package/dist/cohere.cjs.map +1 -0
  74. package/dist/cohere.d.cts +34 -0
  75. package/dist/cohere.d.cts.map +1 -0
  76. package/dist/cohere.d.ts +34 -0
  77. package/dist/cohere.d.ts.map +1 -0
  78. package/dist/cohere.js +433 -0
  79. package/dist/cohere.js.map +1 -0
  80. package/dist/config-loader.cjs +111 -0
  81. package/dist/config-loader.cjs.map +1 -0
  82. package/dist/config-loader.d.cts +100 -0
  83. package/dist/config-loader.d.cts.map +1 -0
  84. package/dist/config-loader.d.ts +100 -0
  85. package/dist/config-loader.d.ts.map +1 -0
  86. package/dist/config-loader.js +107 -0
  87. package/dist/config-loader.js.map +1 -0
  88. package/dist/embeddings.cjs +150 -0
  89. package/dist/embeddings.cjs.map +1 -0
  90. package/dist/embeddings.d.cts +12 -0
  91. package/dist/embeddings.d.cts.map +1 -0
  92. package/dist/embeddings.d.ts +12 -0
  93. package/dist/embeddings.d.ts.map +1 -0
  94. package/dist/embeddings.js +150 -0
  95. package/dist/embeddings.js.map +1 -0
  96. package/dist/fixture-loader.cjs +269 -0
  97. package/dist/fixture-loader.cjs.map +1 -0
  98. package/dist/fixture-loader.d.cts +17 -0
  99. package/dist/fixture-loader.d.cts.map +1 -0
  100. package/dist/fixture-loader.d.ts +17 -0
  101. package/dist/fixture-loader.d.ts.map +1 -0
  102. package/dist/fixture-loader.js +265 -0
  103. package/dist/fixture-loader.js.map +1 -0
  104. package/dist/gemini.cjs +403 -0
  105. package/dist/gemini.cjs.map +1 -0
  106. package/dist/gemini.d.cts +10 -0
  107. package/dist/gemini.d.cts.map +1 -0
  108. package/dist/gemini.d.ts +10 -0
  109. package/dist/gemini.d.ts.map +1 -0
  110. package/dist/gemini.js +403 -0
  111. package/dist/gemini.js.map +1 -0
  112. package/dist/helpers.cjs +276 -0
  113. package/dist/helpers.cjs.map +1 -0
  114. package/dist/helpers.d.cts +39 -0
  115. package/dist/helpers.d.cts.map +1 -0
  116. package/dist/helpers.d.ts +39 -0
  117. package/dist/helpers.d.ts.map +1 -0
  118. package/dist/helpers.js +259 -0
  119. package/dist/helpers.js.map +1 -0
  120. package/dist/index.cjs +113 -0
  121. package/dist/index.d.cts +42 -0
  122. package/dist/index.d.ts +42 -0
  123. package/dist/index.js +39 -0
  124. package/dist/interruption.cjs +40 -0
  125. package/dist/interruption.cjs.map +1 -0
  126. package/dist/interruption.d.cts +15 -0
  127. package/dist/interruption.d.cts.map +1 -0
  128. package/dist/interruption.d.ts +15 -0
  129. package/dist/interruption.d.ts.map +1 -0
  130. package/dist/interruption.js +39 -0
  131. package/dist/interruption.js.map +1 -0
  132. package/dist/journal.cjs +65 -0
  133. package/dist/journal.cjs.map +1 -0
  134. package/dist/journal.d.cts +23 -0
  135. package/dist/journal.d.cts.map +1 -0
  136. package/dist/journal.d.ts +23 -0
  137. package/dist/journal.d.ts.map +1 -0
  138. package/dist/journal.js +65 -0
  139. package/dist/journal.js.map +1 -0
  140. package/dist/jsonrpc.cjs +91 -0
  141. package/dist/jsonrpc.cjs.map +1 -0
  142. package/dist/jsonrpc.d.cts +24 -0
  143. package/dist/jsonrpc.d.cts.map +1 -0
  144. package/dist/jsonrpc.d.ts +24 -0
  145. package/dist/jsonrpc.d.ts.map +1 -0
  146. package/dist/jsonrpc.js +90 -0
  147. package/dist/jsonrpc.js.map +1 -0
  148. package/dist/llmock.cjs +223 -0
  149. package/dist/llmock.cjs.map +1 -0
  150. package/dist/llmock.d.cts +70 -0
  151. package/dist/llmock.d.cts.map +1 -0
  152. package/dist/llmock.d.ts +70 -0
  153. package/dist/llmock.d.ts.map +1 -0
  154. package/dist/llmock.js +223 -0
  155. package/dist/llmock.js.map +1 -0
  156. package/dist/logger.cjs +29 -0
  157. package/dist/logger.cjs.map +1 -0
  158. package/dist/logger.d.cts +14 -0
  159. package/dist/logger.d.cts.map +1 -0
  160. package/dist/logger.d.ts +14 -0
  161. package/dist/logger.d.ts.map +1 -0
  162. package/dist/logger.js +28 -0
  163. package/dist/logger.js.map +1 -0
  164. package/dist/mcp-handler.cjs +189 -0
  165. package/dist/mcp-handler.cjs.map +1 -0
  166. package/dist/mcp-handler.js +188 -0
  167. package/dist/mcp-handler.js.map +1 -0
  168. package/dist/mcp-mock.cjs +169 -0
  169. package/dist/mcp-mock.cjs.map +1 -0
  170. package/dist/mcp-mock.d.cts +40 -0
  171. package/dist/mcp-mock.d.cts.map +1 -0
  172. package/dist/mcp-mock.d.ts +40 -0
  173. package/dist/mcp-mock.d.ts.map +1 -0
  174. package/dist/mcp-mock.js +167 -0
  175. package/dist/mcp-mock.js.map +1 -0
  176. package/dist/mcp-stub.cjs +4 -0
  177. package/dist/mcp-stub.d.cts +3 -0
  178. package/dist/mcp-stub.d.ts +3 -0
  179. package/dist/mcp-stub.js +3 -0
  180. package/dist/mcp-types.d.cts +65 -0
  181. package/dist/mcp-types.d.cts.map +1 -0
  182. package/dist/mcp-types.d.ts +65 -0
  183. package/dist/mcp-types.d.ts.map +1 -0
  184. package/dist/messages.cjs +489 -0
  185. package/dist/messages.cjs.map +1 -0
  186. package/dist/messages.d.cts +10 -0
  187. package/dist/messages.d.cts.map +1 -0
  188. package/dist/messages.d.ts +10 -0
  189. package/dist/messages.d.ts.map +1 -0
  190. package/dist/messages.js +489 -0
  191. package/dist/messages.js.map +1 -0
  192. package/dist/metrics.cjs +160 -0
  193. package/dist/metrics.cjs.map +1 -0
  194. package/dist/metrics.d.cts +24 -0
  195. package/dist/metrics.d.cts.map +1 -0
  196. package/dist/metrics.d.ts +24 -0
  197. package/dist/metrics.d.ts.map +1 -0
  198. package/dist/metrics.js +158 -0
  199. package/dist/metrics.js.map +1 -0
  200. package/dist/moderation.cjs +91 -0
  201. package/dist/moderation.cjs.map +1 -0
  202. package/dist/moderation.d.cts +23 -0
  203. package/dist/moderation.d.cts.map +1 -0
  204. package/dist/moderation.d.ts +23 -0
  205. package/dist/moderation.d.ts.map +1 -0
  206. package/dist/moderation.js +91 -0
  207. package/dist/moderation.js.map +1 -0
  208. package/dist/ndjson-writer.cjs +31 -0
  209. package/dist/ndjson-writer.cjs.map +1 -0
  210. package/dist/ndjson-writer.d.cts +17 -0
  211. package/dist/ndjson-writer.d.cts.map +1 -0
  212. package/dist/ndjson-writer.d.ts +17 -0
  213. package/dist/ndjson-writer.d.ts.map +1 -0
  214. package/dist/ndjson-writer.js +31 -0
  215. package/dist/ndjson-writer.js.map +1 -0
  216. package/dist/ollama.cjs +519 -0
  217. package/dist/ollama.cjs.map +1 -0
  218. package/dist/ollama.d.cts +34 -0
  219. package/dist/ollama.d.cts.map +1 -0
  220. package/dist/ollama.d.ts +34 -0
  221. package/dist/ollama.d.ts.map +1 -0
  222. package/dist/ollama.js +517 -0
  223. package/dist/ollama.js.map +1 -0
  224. package/dist/recorder.cjs +311 -0
  225. package/dist/recorder.cjs.map +1 -0
  226. package/dist/recorder.d.cts +23 -0
  227. package/dist/recorder.d.cts.map +1 -0
  228. package/dist/recorder.d.ts +23 -0
  229. package/dist/recorder.d.ts.map +1 -0
  230. package/dist/recorder.js +305 -0
  231. package/dist/recorder.js.map +1 -0
  232. package/dist/rerank.cjs +71 -0
  233. package/dist/rerank.cjs.map +1 -0
  234. package/dist/rerank.d.cts +22 -0
  235. package/dist/rerank.d.cts.map +1 -0
  236. package/dist/rerank.d.ts +22 -0
  237. package/dist/rerank.d.ts.map +1 -0
  238. package/dist/rerank.js +71 -0
  239. package/dist/rerank.js.map +1 -0
  240. package/dist/responses.cjs +637 -0
  241. package/dist/responses.cjs.map +1 -0
  242. package/dist/responses.d.cts +16 -0
  243. package/dist/responses.d.cts.map +1 -0
  244. package/dist/responses.d.ts +16 -0
  245. package/dist/responses.d.ts.map +1 -0
  246. package/dist/responses.js +634 -0
  247. package/dist/responses.js.map +1 -0
  248. package/dist/router.cjs +68 -0
  249. package/dist/router.cjs.map +1 -0
  250. package/dist/router.d.cts +16 -0
  251. package/dist/router.d.cts.map +1 -0
  252. package/dist/router.d.ts +16 -0
  253. package/dist/router.d.ts.map +1 -0
  254. package/dist/router.js +65 -0
  255. package/dist/router.js.map +1 -0
  256. package/dist/search.cjs +59 -0
  257. package/dist/search.cjs.map +1 -0
  258. package/dist/search.d.cts +23 -0
  259. package/dist/search.d.cts.map +1 -0
  260. package/dist/search.d.ts +23 -0
  261. package/dist/search.d.ts.map +1 -0
  262. package/dist/search.js +59 -0
  263. package/dist/search.js.map +1 -0
  264. package/dist/server.cjs +935 -0
  265. package/dist/server.cjs.map +1 -0
  266. package/dist/server.d.cts +28 -0
  267. package/dist/server.d.cts.map +1 -0
  268. package/dist/server.d.ts +28 -0
  269. package/dist/server.d.ts.map +1 -0
  270. package/dist/server.js +933 -0
  271. package/dist/server.js.map +1 -0
  272. package/dist/sse-writer.cjs +59 -0
  273. package/dist/sse-writer.cjs.map +1 -0
  274. package/dist/sse-writer.d.cts +19 -0
  275. package/dist/sse-writer.d.cts.map +1 -0
  276. package/dist/sse-writer.d.ts +19 -0
  277. package/dist/sse-writer.d.ts.map +1 -0
  278. package/dist/sse-writer.js +55 -0
  279. package/dist/sse-writer.js.map +1 -0
  280. package/dist/stream-collapse.cjs +496 -0
  281. package/dist/stream-collapse.cjs.map +1 -0
  282. package/dist/stream-collapse.d.cts +70 -0
  283. package/dist/stream-collapse.d.cts.map +1 -0
  284. package/dist/stream-collapse.d.ts +70 -0
  285. package/dist/stream-collapse.d.ts.map +1 -0
  286. package/dist/stream-collapse.js +489 -0
  287. package/dist/stream-collapse.js.map +1 -0
  288. package/dist/suite.cjs +46 -0
  289. package/dist/suite.cjs.map +1 -0
  290. package/dist/suite.d.cts +31 -0
  291. package/dist/suite.d.cts.map +1 -0
  292. package/dist/suite.d.ts +31 -0
  293. package/dist/suite.d.ts.map +1 -0
  294. package/dist/suite.js +46 -0
  295. package/dist/suite.js.map +1 -0
  296. package/dist/types.d.cts +243 -0
  297. package/dist/types.d.cts.map +1 -0
  298. package/dist/types.d.ts +243 -0
  299. package/dist/types.d.ts.map +1 -0
  300. package/dist/url.cjs +21 -0
  301. package/dist/url.cjs.map +1 -0
  302. package/dist/url.d.cts +16 -0
  303. package/dist/url.d.cts.map +1 -0
  304. package/dist/url.d.ts +16 -0
  305. package/dist/url.d.ts.map +1 -0
  306. package/dist/url.js +20 -0
  307. package/dist/url.js.map +1 -0
  308. package/dist/vector-handler.cjs +239 -0
  309. package/dist/vector-handler.cjs.map +1 -0
  310. package/dist/vector-handler.js +238 -0
  311. package/dist/vector-handler.js.map +1 -0
  312. package/dist/vector-mock.cjs +229 -0
  313. package/dist/vector-mock.cjs.map +1 -0
  314. package/dist/vector-mock.d.cts +39 -0
  315. package/dist/vector-mock.d.cts.map +1 -0
  316. package/dist/vector-mock.d.ts +39 -0
  317. package/dist/vector-mock.d.ts.map +1 -0
  318. package/dist/vector-mock.js +227 -0
  319. package/dist/vector-mock.js.map +1 -0
  320. package/dist/vector-stub.cjs +4 -0
  321. package/dist/vector-stub.d.cts +3 -0
  322. package/dist/vector-stub.d.ts +3 -0
  323. package/dist/vector-stub.js +3 -0
  324. package/dist/vector-types.d.cts +32 -0
  325. package/dist/vector-types.d.cts.map +1 -0
  326. package/dist/vector-types.d.ts +32 -0
  327. package/dist/vector-types.d.ts.map +1 -0
  328. package/dist/watcher.cjs +59 -0
  329. package/dist/watcher.cjs.map +1 -0
  330. package/dist/watcher.js +58 -0
  331. package/dist/watcher.js.map +1 -0
  332. package/dist/ws-framing.cjs +187 -0
  333. package/dist/ws-framing.cjs.map +1 -0
  334. package/dist/ws-framing.d.cts +26 -0
  335. package/dist/ws-framing.d.cts.map +1 -0
  336. package/dist/ws-framing.d.ts +26 -0
  337. package/dist/ws-framing.d.ts.map +1 -0
  338. package/dist/ws-framing.js +184 -0
  339. package/dist/ws-framing.js.map +1 -0
  340. package/dist/ws-gemini-live.cjs +364 -0
  341. package/dist/ws-gemini-live.cjs.map +1 -0
  342. package/dist/ws-gemini-live.d.cts +18 -0
  343. package/dist/ws-gemini-live.d.cts.map +1 -0
  344. package/dist/ws-gemini-live.d.ts +18 -0
  345. package/dist/ws-gemini-live.d.ts.map +1 -0
  346. package/dist/ws-gemini-live.js +364 -0
  347. package/dist/ws-gemini-live.js.map +1 -0
  348. package/dist/ws-realtime.cjs +435 -0
  349. package/dist/ws-realtime.cjs.map +1 -0
  350. package/dist/ws-realtime.d.cts +17 -0
  351. package/dist/ws-realtime.d.cts.map +1 -0
  352. package/dist/ws-realtime.d.ts +17 -0
  353. package/dist/ws-realtime.d.ts.map +1 -0
  354. package/dist/ws-realtime.js +435 -0
  355. package/dist/ws-realtime.js.map +1 -0
  356. package/dist/ws-responses.cjs +164 -0
  357. package/dist/ws-responses.cjs.map +1 -0
  358. package/dist/ws-responses.d.cts +18 -0
  359. package/dist/ws-responses.d.cts.map +1 -0
  360. package/dist/ws-responses.d.ts +18 -0
  361. package/dist/ws-responses.d.ts.map +1 -0
  362. package/dist/ws-responses.js +164 -0
  363. package/dist/ws-responses.js.map +1 -0
  364. package/fixtures/example-greeting.json +12 -0
  365. package/fixtures/example-multi-turn.json +14 -0
  366. package/fixtures/example-tool-call.json +15 -0
  367. package/package.json +118 -0
  368. package/skills/write-fixtures/SKILL.md +625 -0
@@ -0,0 +1,188 @@
1
+ import { createJsonRpcDispatcher } from "./jsonrpc.js";
2
+ import { randomUUID } from "node:crypto";
3
+
4
+ //#region src/mcp-handler.ts
5
+ function jsonRpcResult(id, result) {
6
+ return {
7
+ jsonrpc: "2.0",
8
+ id,
9
+ result
10
+ };
11
+ }
12
+ function jsonRpcError(id, code, message) {
13
+ return {
14
+ jsonrpc: "2.0",
15
+ id,
16
+ error: {
17
+ code,
18
+ message
19
+ }
20
+ };
21
+ }
22
+ function createMCPRequestHandler(state) {
23
+ const dispatcher = createJsonRpcDispatcher({ methods: {
24
+ initialize: async (_params, id) => {
25
+ return jsonRpcResult(id, {
26
+ protocolVersion: "2025-03-26",
27
+ capabilities: {
28
+ tools: {},
29
+ resources: {},
30
+ prompts: {}
31
+ },
32
+ serverInfo: state.serverInfo
33
+ });
34
+ },
35
+ "notifications/initialized": async (_params, _id, req) => {
36
+ const sessionId = req.headers["mcp-session-id"];
37
+ const session = state.sessions.get(sessionId);
38
+ if (session) session.initialized = true;
39
+ return null;
40
+ },
41
+ ping: async (_params, id) => {
42
+ return jsonRpcResult(id, {});
43
+ },
44
+ "tools/list": async (_params, id) => {
45
+ const tools = [];
46
+ for (const { def } of state.tools.values()) tools.push(def);
47
+ return jsonRpcResult(id, { tools });
48
+ },
49
+ "tools/call": async (params, id) => {
50
+ const { name, arguments: args } = params ?? {};
51
+ if (!name) return jsonRpcError(id, -32602, "Missing tool name");
52
+ const entry = state.tools.get(name);
53
+ if (!entry) return jsonRpcError(id, -32602, `Unknown tool: ${name}`);
54
+ if (entry.handler) try {
55
+ const result = await entry.handler(args);
56
+ return jsonRpcResult(id, {
57
+ content: Array.isArray(result) ? result : [{
58
+ type: "text",
59
+ text: String(result)
60
+ }],
61
+ isError: false
62
+ });
63
+ } catch (err) {
64
+ return jsonRpcResult(id, {
65
+ content: [{
66
+ type: "text",
67
+ text: err instanceof Error ? err.message : String(err)
68
+ }],
69
+ isError: true
70
+ });
71
+ }
72
+ return jsonRpcResult(id, {
73
+ content: [],
74
+ isError: false
75
+ });
76
+ },
77
+ "resources/list": async (_params, id) => {
78
+ const resources = [];
79
+ for (const { def } of state.resources.values()) resources.push(def);
80
+ return jsonRpcResult(id, { resources });
81
+ },
82
+ "resources/read": async (params, id) => {
83
+ const { uri } = params ?? {};
84
+ if (!uri) return jsonRpcError(id, -32602, "Missing resource URI");
85
+ const entry = state.resources.get(uri);
86
+ if (!entry) return jsonRpcError(id, -32602, `Unknown resource: ${uri}`);
87
+ return jsonRpcResult(id, { contents: [{
88
+ uri,
89
+ ...entry.content?.text !== void 0 && { text: entry.content.text },
90
+ ...entry.content?.blob !== void 0 && { blob: entry.content.blob },
91
+ ...entry.content?.mimeType !== void 0 && { mimeType: entry.content.mimeType }
92
+ }] });
93
+ },
94
+ "prompts/list": async (_params, id) => {
95
+ const prompts = [];
96
+ for (const { def } of state.prompts.values()) prompts.push(def);
97
+ return jsonRpcResult(id, { prompts });
98
+ },
99
+ "prompts/get": async (params, id) => {
100
+ const { name, arguments: args } = params ?? {};
101
+ if (!name) return jsonRpcError(id, -32602, "Missing prompt name");
102
+ const entry = state.prompts.get(name);
103
+ if (!entry) return jsonRpcError(id, -32602, `Unknown prompt: ${name}`);
104
+ if (entry.handler) try {
105
+ return jsonRpcResult(id, await entry.handler(args));
106
+ } catch (err) {
107
+ return jsonRpcError(id, -32603, `Prompt handler error: ${err instanceof Error ? err.message : String(err)}`);
108
+ }
109
+ return jsonRpcResult(id, { messages: [] });
110
+ }
111
+ } });
112
+ return async (req, res, body) => {
113
+ if (req.method === "DELETE") {
114
+ const sessionId = req.headers["mcp-session-id"];
115
+ if (!sessionId) {
116
+ res.writeHead(400, { "Content-Type": "application/json" });
117
+ res.end(JSON.stringify({ error: "Missing mcp-session-id header" }));
118
+ return;
119
+ }
120
+ if (!state.sessions.has(sessionId)) {
121
+ res.writeHead(404, { "Content-Type": "application/json" });
122
+ res.end(JSON.stringify({ error: "Session not found" }));
123
+ return;
124
+ }
125
+ state.sessions.delete(sessionId);
126
+ res.writeHead(200, { "Content-Type": "application/json" });
127
+ res.end(JSON.stringify({ ok: true }));
128
+ return;
129
+ }
130
+ let parsed;
131
+ try {
132
+ parsed = JSON.parse(body);
133
+ } catch {
134
+ await dispatcher(req, res, body);
135
+ return;
136
+ }
137
+ const method = typeof parsed === "object" && parsed !== null && "method" in parsed ? parsed.method : void 0;
138
+ if (method === "initialize") {
139
+ const id = typeof parsed === "object" && parsed !== null && "id" in parsed ? parsed.id : null;
140
+ const sessionId = randomUUID();
141
+ state.sessions.set(sessionId, {
142
+ id: sessionId,
143
+ initialized: false,
144
+ createdAt: Date.now()
145
+ });
146
+ const response = {
147
+ jsonrpc: "2.0",
148
+ id,
149
+ result: {
150
+ protocolVersion: "2025-03-26",
151
+ capabilities: {
152
+ tools: {},
153
+ resources: {},
154
+ prompts: {}
155
+ },
156
+ serverInfo: state.serverInfo
157
+ }
158
+ };
159
+ res.writeHead(200, {
160
+ "Content-Type": "application/json",
161
+ "Mcp-Session-Id": sessionId
162
+ });
163
+ res.end(JSON.stringify(response));
164
+ return;
165
+ }
166
+ const sessionId = req.headers["mcp-session-id"];
167
+ if (!sessionId) {
168
+ res.writeHead(400, { "Content-Type": "application/json" });
169
+ res.end(JSON.stringify({ error: "Missing mcp-session-id header" }));
170
+ return;
171
+ }
172
+ if (!state.sessions.has(sessionId)) {
173
+ res.writeHead(404, { "Content-Type": "application/json" });
174
+ res.end(JSON.stringify({ error: "Session not found" }));
175
+ return;
176
+ }
177
+ if (!state.sessions.get(sessionId).initialized && method !== "notifications/initialized") {
178
+ res.writeHead(400, { "Content-Type": "application/json" });
179
+ res.end(JSON.stringify(jsonRpcError(typeof parsed === "object" && parsed !== null && "id" in parsed ? parsed.id : null, -32002, "Session not initialized")));
180
+ return;
181
+ }
182
+ await dispatcher(req, res, body);
183
+ };
184
+ }
185
+
186
+ //#endregion
187
+ export { createMCPRequestHandler };
188
+ //# sourceMappingURL=mcp-handler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-handler.js","names":[],"sources":["../src/mcp-handler.ts"],"sourcesContent":["import type * as http from \"node:http\";\nimport { randomUUID } from \"node:crypto\";\nimport { createJsonRpcDispatcher } from \"./jsonrpc.js\";\nimport type {\n MCPToolDefinition,\n MCPResourceDefinition,\n MCPResourceContent,\n MCPPromptDefinition,\n MCPPromptResult,\n MCPContent,\n MCPSession,\n} from \"./mcp-types.js\";\n\nexport interface MCPState {\n serverInfo: { name: string; version: string };\n tools: Map<string, { def: MCPToolDefinition; handler?: (...args: unknown[]) => unknown }>;\n resources: Map<string, { def: MCPResourceDefinition; content?: MCPResourceContent }>;\n prompts: Map<\n string,\n {\n def: MCPPromptDefinition;\n handler?: (...args: unknown[]) => MCPPromptResult | Promise<MCPPromptResult>;\n }\n >;\n sessions: Map<string, MCPSession>;\n}\n\nfunction jsonRpcResult(id: string | number, result: unknown) {\n return { jsonrpc: \"2.0\" as const, id, result };\n}\n\nfunction jsonRpcError(id: string | number | null, code: number, message: string) {\n return { jsonrpc: \"2.0\" as const, id, error: { code, message } };\n}\n\nexport function createMCPRequestHandler(state: MCPState) {\n const dispatcher = createJsonRpcDispatcher({\n methods: {\n // initialize is handled directly in the outer function — this entry is\n // only here so the dispatcher doesn't return \"Method not found\" if the\n // request somehow reaches it.\n initialize: async (_params, id) => {\n return jsonRpcResult(id, {\n protocolVersion: \"2025-03-26\",\n capabilities: { tools: {}, resources: {}, prompts: {} },\n serverInfo: state.serverInfo,\n });\n },\n\n \"notifications/initialized\": async (_params, _id, req) => {\n const sessionId = req.headers[\"mcp-session-id\"] as string;\n const session = state.sessions.get(sessionId);\n if (session) {\n session.initialized = true;\n }\n return null;\n },\n\n ping: async (_params, id) => {\n return jsonRpcResult(id, {});\n },\n\n \"tools/list\": async (_params, id) => {\n const tools: MCPToolDefinition[] = [];\n for (const { def } of state.tools.values()) {\n tools.push(def);\n }\n return jsonRpcResult(id, { tools });\n },\n\n \"tools/call\": async (params, id) => {\n const { name, arguments: args } = (params ?? {}) as { name?: string; arguments?: unknown };\n if (!name) {\n return jsonRpcError(id, -32602, \"Missing tool name\");\n }\n const entry = state.tools.get(name);\n if (!entry) {\n return jsonRpcError(id, -32602, `Unknown tool: ${name}`);\n }\n if (entry.handler) {\n try {\n const result = await entry.handler(args);\n const content: MCPContent[] = Array.isArray(result)\n ? result\n : [{ type: \"text\", text: String(result) }];\n return jsonRpcResult(id, { content, isError: false });\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n return jsonRpcResult(id, {\n content: [{ type: \"text\", text: message }],\n isError: true,\n });\n }\n }\n // No handler — return empty content\n return jsonRpcResult(id, { content: [], isError: false });\n },\n\n \"resources/list\": async (_params, id) => {\n const resources: MCPResourceDefinition[] = [];\n for (const { def } of state.resources.values()) {\n resources.push(def);\n }\n return jsonRpcResult(id, { resources });\n },\n\n \"resources/read\": async (params, id) => {\n const { uri } = (params ?? {}) as { uri?: string };\n if (!uri) {\n return jsonRpcError(id, -32602, \"Missing resource URI\");\n }\n const entry = state.resources.get(uri);\n if (!entry) {\n return jsonRpcError(id, -32602, `Unknown resource: ${uri}`);\n }\n return jsonRpcResult(id, {\n contents: [\n {\n uri,\n ...(entry.content?.text !== undefined && { text: entry.content.text }),\n ...(entry.content?.blob !== undefined && { blob: entry.content.blob }),\n ...(entry.content?.mimeType !== undefined && { mimeType: entry.content.mimeType }),\n },\n ],\n });\n },\n\n \"prompts/list\": async (_params, id) => {\n const prompts: MCPPromptDefinition[] = [];\n for (const { def } of state.prompts.values()) {\n prompts.push(def);\n }\n return jsonRpcResult(id, { prompts });\n },\n\n \"prompts/get\": async (params, id) => {\n const { name, arguments: args } = (params ?? {}) as { name?: string; arguments?: unknown };\n if (!name) {\n return jsonRpcError(id, -32602, \"Missing prompt name\");\n }\n const entry = state.prompts.get(name);\n if (!entry) {\n return jsonRpcError(id, -32602, `Unknown prompt: ${name}`);\n }\n if (entry.handler) {\n try {\n const result = await entry.handler(args);\n return jsonRpcResult(id, result);\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n return jsonRpcError(id, -32603, `Prompt handler error: ${message}`);\n }\n }\n // No handler — return empty messages\n return jsonRpcResult(id, { messages: [] });\n },\n },\n });\n\n return async (\n req: http.IncomingMessage,\n res: http.ServerResponse,\n body: string,\n ): Promise<void> => {\n // DELETE handler: session teardown\n if (req.method === \"DELETE\") {\n const sessionId = req.headers[\"mcp-session-id\"] as string | undefined;\n if (!sessionId) {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Missing mcp-session-id header\" }));\n return;\n }\n if (!state.sessions.has(sessionId)) {\n res.writeHead(404, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Session not found\" }));\n return;\n }\n state.sessions.delete(sessionId);\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ ok: true }));\n return;\n }\n\n // Parse the body to determine method for session validation\n let parsed: unknown;\n try {\n parsed = JSON.parse(body);\n } catch {\n // Let the dispatcher handle parse errors\n await dispatcher(req, res, body);\n return;\n }\n\n const method =\n typeof parsed === \"object\" && parsed !== null && \"method\" in parsed\n ? (parsed as { method: unknown }).method\n : undefined;\n\n // Handle initialize directly to control response headers\n if (method === \"initialize\") {\n const id =\n typeof parsed === \"object\" && parsed !== null && \"id\" in parsed\n ? (parsed as { id: unknown }).id\n : null;\n\n const sessionId = randomUUID();\n state.sessions.set(sessionId, {\n id: sessionId,\n initialized: false,\n createdAt: Date.now(),\n });\n\n const response = {\n jsonrpc: \"2.0\",\n id,\n result: {\n protocolVersion: \"2025-03-26\",\n capabilities: { tools: {}, resources: {}, prompts: {} },\n serverInfo: state.serverInfo,\n },\n };\n\n res.writeHead(200, {\n \"Content-Type\": \"application/json\",\n \"Mcp-Session-Id\": sessionId,\n });\n res.end(JSON.stringify(response));\n return;\n }\n\n // Session validation for all other methods\n const sessionId = req.headers[\"mcp-session-id\"] as string | undefined;\n if (!sessionId) {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Missing mcp-session-id header\" }));\n return;\n }\n if (!state.sessions.has(sessionId)) {\n res.writeHead(404, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Session not found\" }));\n return;\n }\n\n // Enforce initialization: only allow notifications/initialized through\n // before the session is fully initialized\n const session = state.sessions.get(sessionId)!;\n if (!session.initialized && method !== \"notifications/initialized\") {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify(\n jsonRpcError(\n typeof parsed === \"object\" && parsed !== null && \"id\" in parsed\n ? ((parsed as { id: unknown }).id as string | number)\n : null,\n -32002,\n \"Session not initialized\",\n ),\n ),\n );\n return;\n }\n\n // Delegate to the JSON-RPC dispatcher for all other methods\n await dispatcher(req, res, body);\n };\n}\n"],"mappings":"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"}
@@ -0,0 +1,169 @@
1
+ const require_runtime = require('./_virtual/_rolldown/runtime.cjs');
2
+ const require_helpers = require('./helpers.cjs');
3
+ const require_mcp_handler = require('./mcp-handler.cjs');
4
+ let node_http = require("node:http");
5
+ node_http = require_runtime.__toESM(node_http);
6
+
7
+ //#region src/mcp-mock.ts
8
+ var MCPMock = class {
9
+ tools = /* @__PURE__ */ new Map();
10
+ resources = /* @__PURE__ */ new Map();
11
+ prompts = /* @__PURE__ */ new Map();
12
+ sessions = /* @__PURE__ */ new Map();
13
+ server = null;
14
+ journal = null;
15
+ registry = null;
16
+ options;
17
+ requestHandler;
18
+ constructor(options) {
19
+ this.options = options ?? {};
20
+ this.requestHandler = this.buildHandler();
21
+ }
22
+ addTool(def) {
23
+ this.tools.set(def.name, { def });
24
+ return this;
25
+ }
26
+ onToolCall(name, handler) {
27
+ const entry = this.tools.get(name);
28
+ if (entry) entry.handler = handler;
29
+ else this.tools.set(name, {
30
+ def: { name },
31
+ handler
32
+ });
33
+ return this;
34
+ }
35
+ addResource(def, content) {
36
+ this.resources.set(def.uri, {
37
+ def,
38
+ content
39
+ });
40
+ return this;
41
+ }
42
+ addPrompt(def, handler) {
43
+ this.prompts.set(def.name, {
44
+ def,
45
+ handler
46
+ });
47
+ return this;
48
+ }
49
+ async handleRequest(req, res, pathname) {
50
+ if (pathname !== "/" && pathname !== "") return false;
51
+ if (req.method !== "POST" && req.method !== "DELETE") return false;
52
+ const body = await require_helpers.readBody(req);
53
+ if (this.registry) if (req.method === "DELETE") this.registry.incrementCounter("aimock_mcp_requests_total", { method: "session/delete" });
54
+ else try {
55
+ const parsed = JSON.parse(body);
56
+ const method = typeof parsed === "object" && parsed !== null && "method" in parsed ? String(parsed.method) : "unknown";
57
+ this.registry.incrementCounter("aimock_mcp_requests_total", { method });
58
+ } catch {
59
+ this.registry.incrementCounter("aimock_mcp_requests_total", { method: "unknown" });
60
+ }
61
+ await this.requestHandler(req, res, body);
62
+ if (this.journal) this.journal.add({
63
+ method: req.method ?? "POST",
64
+ path: req.url ?? "/",
65
+ headers: require_helpers.flattenHeaders(req.headers),
66
+ body: null,
67
+ service: "mcp",
68
+ response: {
69
+ status: res.statusCode,
70
+ fixture: null
71
+ }
72
+ });
73
+ return true;
74
+ }
75
+ health() {
76
+ return {
77
+ status: "ok",
78
+ tools: this.tools.size,
79
+ resources: this.resources.size,
80
+ prompts: this.prompts.size,
81
+ sessions: this.sessions.size
82
+ };
83
+ }
84
+ setJournal(journal) {
85
+ this.journal = journal;
86
+ }
87
+ setRegistry(registry) {
88
+ this.registry = registry;
89
+ }
90
+ async start() {
91
+ if (this.server) throw new Error("Server already started");
92
+ const host = this.options.host ?? "127.0.0.1";
93
+ const port = this.options.port ?? 0;
94
+ return new Promise((resolve, reject) => {
95
+ const srv = node_http.createServer((req, res) => {
96
+ const chunks = [];
97
+ req.on("data", (chunk) => chunks.push(chunk));
98
+ req.on("end", () => {
99
+ const body = Buffer.concat(chunks).toString();
100
+ this.requestHandler(req, res, body).then(() => {
101
+ if (this.journal) this.journal.add({
102
+ method: req.method ?? "POST",
103
+ path: req.url ?? "/",
104
+ headers: require_helpers.flattenHeaders(req.headers),
105
+ body: null,
106
+ service: "mcp",
107
+ response: {
108
+ status: res.statusCode,
109
+ fixture: null
110
+ }
111
+ });
112
+ }).catch((err) => {
113
+ console.error("MCPMock request error:", err);
114
+ if (!res.headersSent) {
115
+ res.writeHead(500);
116
+ res.end("Internal server error");
117
+ }
118
+ });
119
+ });
120
+ });
121
+ srv.listen(port, host, () => {
122
+ this.server = srv;
123
+ const addr = srv.address();
124
+ if (typeof addr === "object" && addr !== null) resolve(`http://${host}:${addr.port}`);
125
+ else resolve(`http://${host}:${port}`);
126
+ });
127
+ srv.on("error", reject);
128
+ });
129
+ }
130
+ async stop() {
131
+ if (!this.server) throw new Error("Server not started");
132
+ const srv = this.server;
133
+ this.server = null;
134
+ await new Promise((resolve, reject) => {
135
+ srv.close((err) => err ? reject(err) : resolve());
136
+ });
137
+ }
138
+ getRequests() {
139
+ if (!this.journal) return [];
140
+ return this.journal.getAll().filter((e) => e.service === "mcp");
141
+ }
142
+ getSessions() {
143
+ return new Map(this.sessions);
144
+ }
145
+ reset() {
146
+ this.tools.clear();
147
+ this.resources.clear();
148
+ this.prompts.clear();
149
+ this.sessions.clear();
150
+ this.requestHandler = this.buildHandler();
151
+ return this;
152
+ }
153
+ buildHandler() {
154
+ return require_mcp_handler.createMCPRequestHandler({
155
+ serverInfo: this.options.serverInfo ?? {
156
+ name: "mcp-mock",
157
+ version: "1.0.0"
158
+ },
159
+ tools: this.tools,
160
+ resources: this.resources,
161
+ prompts: this.prompts,
162
+ sessions: this.sessions
163
+ });
164
+ }
165
+ };
166
+
167
+ //#endregion
168
+ exports.MCPMock = MCPMock;
169
+ //# sourceMappingURL=mcp-mock.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-mock.cjs","names":["readBody","flattenHeaders","http","createMCPRequestHandler"],"sources":["../src/mcp-mock.ts"],"sourcesContent":["import * as http from \"node:http\";\nimport type { Mountable } from \"./types.js\";\nimport type { Journal } from \"./journal.js\";\nimport type { MetricsRegistry } from \"./metrics.js\";\nimport type {\n MCPMockOptions,\n MCPToolDefinition,\n MCPResourceDefinition,\n MCPResourceContent,\n MCPPromptDefinition,\n MCPPromptResult,\n MCPContent,\n MCPSession,\n} from \"./mcp-types.js\";\nimport { createMCPRequestHandler, type MCPState } from \"./mcp-handler.js\";\nimport { flattenHeaders, readBody } from \"./helpers.js\";\n\nexport class MCPMock implements Mountable {\n private tools: Map<\n string,\n { def: MCPToolDefinition; handler?: (...args: unknown[]) => unknown }\n > = new Map();\n private resources: Map<string, { def: MCPResourceDefinition; content?: MCPResourceContent }> =\n new Map();\n private prompts: Map<\n string,\n {\n def: MCPPromptDefinition;\n handler?: (...args: unknown[]) => MCPPromptResult | Promise<MCPPromptResult>;\n }\n > = new Map();\n private sessions: Map<string, MCPSession> = new Map();\n private server: http.Server | null = null;\n private journal: Journal | null = null;\n private registry: MetricsRegistry | null = null;\n private options: MCPMockOptions;\n private requestHandler: ReturnType<typeof createMCPRequestHandler>;\n\n constructor(options?: MCPMockOptions) {\n this.options = options ?? {};\n this.requestHandler = this.buildHandler();\n }\n\n // ---- Configuration: Tools ----\n\n addTool(def: MCPToolDefinition): this {\n this.tools.set(def.name, { def });\n return this;\n }\n\n onToolCall(\n name: string,\n handler: (args: unknown) => MCPContent[] | string | Promise<MCPContent[] | string>,\n ): this {\n const entry = this.tools.get(name);\n if (entry) {\n entry.handler = handler;\n } else {\n this.tools.set(name, { def: { name }, handler });\n }\n return this;\n }\n\n // ---- Configuration: Resources ----\n\n addResource(def: MCPResourceDefinition, content?: MCPResourceContent): this {\n this.resources.set(def.uri, { def, content });\n return this;\n }\n\n // ---- Configuration: Prompts ----\n\n addPrompt(\n def: MCPPromptDefinition,\n handler?: (args: unknown) => MCPPromptResult | Promise<MCPPromptResult>,\n ): this {\n this.prompts.set(def.name, { def, handler });\n return this;\n }\n\n // ---- Mountable interface ----\n\n async handleRequest(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n pathname: string,\n ): Promise<boolean> {\n // Only handle POST and DELETE to the root of the mount\n if (pathname !== \"/\" && pathname !== \"\") {\n return false;\n }\n if (req.method !== \"POST\" && req.method !== \"DELETE\") {\n return false;\n }\n\n const body = await readBody(req);\n\n // Extract JSON-RPC method for metrics (skip for DELETE — no JSON-RPC body)\n if (this.registry) {\n if (req.method === \"DELETE\") {\n this.registry.incrementCounter(\"aimock_mcp_requests_total\", { method: \"session/delete\" });\n } else {\n try {\n const parsed = JSON.parse(body);\n const method =\n typeof parsed === \"object\" && parsed !== null && \"method\" in parsed\n ? String(parsed.method)\n : \"unknown\";\n this.registry.incrementCounter(\"aimock_mcp_requests_total\", { method });\n } catch {\n this.registry.incrementCounter(\"aimock_mcp_requests_total\", { method: \"unknown\" });\n }\n }\n }\n\n await this.requestHandler(req, res, body);\n\n // Journal the request after the handler completes\n if (this.journal) {\n this.journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/\",\n headers: flattenHeaders(req.headers),\n body: null,\n service: \"mcp\",\n response: { status: res.statusCode, fixture: null },\n });\n }\n\n return true;\n }\n\n health(): { status: string; [key: string]: unknown } {\n return {\n status: \"ok\",\n tools: this.tools.size,\n resources: this.resources.size,\n prompts: this.prompts.size,\n sessions: this.sessions.size,\n };\n }\n\n setJournal(journal: Journal): void {\n this.journal = journal;\n }\n\n setRegistry(registry: MetricsRegistry): void {\n this.registry = registry;\n }\n\n // ---- Standalone mode ----\n\n async start(): Promise<string> {\n if (this.server) {\n throw new Error(\"Server already started\");\n }\n\n const host = this.options.host ?? \"127.0.0.1\";\n const port = this.options.port ?? 0;\n\n return new Promise((resolve, reject) => {\n const srv = http.createServer((req, res) => {\n const chunks: Buffer[] = [];\n req.on(\"data\", (chunk: Buffer) => chunks.push(chunk));\n req.on(\"end\", () => {\n const body = Buffer.concat(chunks).toString();\n\n this.requestHandler(req, res, body)\n .then(() => {\n if (this.journal) {\n this.journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/\",\n headers: flattenHeaders(req.headers),\n body: null,\n service: \"mcp\",\n response: { status: res.statusCode, fixture: null },\n });\n }\n })\n .catch((err) => {\n console.error(\"MCPMock request error:\", err);\n if (!res.headersSent) {\n res.writeHead(500);\n res.end(\"Internal server error\");\n }\n });\n });\n });\n\n srv.listen(port, host, () => {\n this.server = srv;\n const addr = srv.address();\n if (typeof addr === \"object\" && addr !== null) {\n resolve(`http://${host}:${addr.port}`);\n } else {\n resolve(`http://${host}:${port}`);\n }\n });\n\n srv.on(\"error\", reject);\n });\n }\n\n async stop(): Promise<void> {\n if (!this.server) {\n throw new Error(\"Server not started\");\n }\n const srv = this.server;\n this.server = null;\n await new Promise<void>((resolve, reject) => {\n srv.close((err) => (err ? reject(err) : resolve()));\n });\n }\n\n // ---- Inspection ----\n\n getRequests(): unknown[] {\n if (!this.journal) return [];\n return this.journal.getAll().filter((e) => e.service === \"mcp\");\n }\n\n getSessions(): Map<string, MCPSession> {\n return new Map(this.sessions);\n }\n\n reset(): this {\n this.tools.clear();\n this.resources.clear();\n this.prompts.clear();\n this.sessions.clear();\n this.requestHandler = this.buildHandler();\n return this;\n }\n\n // ---- Internal ----\n\n private buildHandler() {\n const state: MCPState = {\n serverInfo: this.options.serverInfo ?? { name: \"mcp-mock\", version: \"1.0.0\" },\n tools: this.tools,\n resources: this.resources,\n prompts: this.prompts,\n sessions: this.sessions,\n };\n return createMCPRequestHandler(state);\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,40 @@
1
+ import { Journal } from "./journal.cjs";
2
+ import { MetricsRegistry } from "./metrics.cjs";
3
+ import { Mountable } from "./types.cjs";
4
+ import { MCPContent, MCPMockOptions, MCPPromptDefinition, MCPPromptResult, MCPResourceContent, MCPResourceDefinition, MCPSession, MCPToolDefinition } from "./mcp-types.cjs";
5
+ import * as http from "node:http";
6
+
7
+ //#region src/mcp-mock.d.ts
8
+ declare class MCPMock implements Mountable {
9
+ private tools;
10
+ private resources;
11
+ private prompts;
12
+ private sessions;
13
+ private server;
14
+ private journal;
15
+ private registry;
16
+ private options;
17
+ private requestHandler;
18
+ constructor(options?: MCPMockOptions);
19
+ addTool(def: MCPToolDefinition): this;
20
+ onToolCall(name: string, handler: (args: unknown) => MCPContent[] | string | Promise<MCPContent[] | string>): this;
21
+ addResource(def: MCPResourceDefinition, content?: MCPResourceContent): this;
22
+ addPrompt(def: MCPPromptDefinition, handler?: (args: unknown) => MCPPromptResult | Promise<MCPPromptResult>): this;
23
+ handleRequest(req: http.IncomingMessage, res: http.ServerResponse, pathname: string): Promise<boolean>;
24
+ health(): {
25
+ status: string;
26
+ [key: string]: unknown;
27
+ };
28
+ setJournal(journal: Journal): void;
29
+ setRegistry(registry: MetricsRegistry): void;
30
+ start(): Promise<string>;
31
+ stop(): Promise<void>;
32
+ getRequests(): unknown[];
33
+ getSessions(): Map<string, MCPSession>;
34
+ reset(): this;
35
+ private buildHandler;
36
+ }
37
+ //# sourceMappingURL=mcp-mock.d.ts.map
38
+ //#endregion
39
+ export { MCPMock };
40
+ //# sourceMappingURL=mcp-mock.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-mock.d.cts","names":[],"sources":["../src/mcp-mock.ts"],"sourcesContent":[],"mappings":";;;;;;;cAiBa,OAAA,YAAmB;;EAAnB,QAAA,SAAQ;EAAA,QAAA,OAAA;UAqBG,QAAA;UAOT,MAAA;UAOiB,OAAA;UAAgC,QAAA;UAAR,OAAA;UAarC,cAAA;aAAiC,CAAA,OAAA,CAAA,EA3B5B,cA2B4B;SAQ3C,CAAA,GAAA,EA5BM,iBA4BN,CAAA,EAAA,IAAA;YACwB,CAAA,IAAA,EAAA,MAAA,EAAA,OAAA,EAAA,CAAA,IAAA,EAAA,OAAA,EAAA,GAtBD,UAsBC,EAAA,GAAA,MAAA,GAtBuB,OAsBvB,CAtB+B,UAsB/B,EAAA,GAAA,MAAA,CAAA,CAAA,EAAA,IAAA;aAA0B,CAAA,GAAA,EATxC,qBASwC,EAAA,OAAA,CAAA,EATP,kBASO,CAAA,EAAA,IAAA;WAAR,CAAA,GAAA,EAD1C,mBAC0C,EAAA,OAAA,CAAA,EAAA,CAAA,IAAA,EAAA,OAAA,EAAA,GAAlB,eAAkB,GAAA,OAAA,CAAQ,eAAR,CAAA,CAAA,EAAA,IAAA;eASrC,CAAA,GAAA,EAAL,IAAA,CAAK,eAAA,EAAA,GAAA,EACL,IAAA,CAAK,cADA,EAAA,QAAA,EAAA,MAAA,CAAA,EAGT,OAHS,CAAA,OAAA,CAAA;QACL,CAAA,CAAK,EAAA;IAET,MAAA,EAAA,MAAA;IAwDiB,CAAA,GAAA,EAAA,MAAA,CAAA,EAAA,OAAA;;YAUL,CAAA,OAAA,EAVK,OAUL,CAAA,EAAA,IAAA;aAoDD,CAAA,QAAA,EA1DQ,eA0DR,CAAA,EAAA,IAAA;OAkBa,CAAA,CAAA,EAtEZ,OAsEY,CAAA,MAAA,CAAA;MAAZ,CAAA,CAAA,EAlBD,OAkBC,CAAA,IAAA,CAAA;aA7Me,CAAA,CAAA,EAAA,OAAA,EAAA;EAAS,WAAA,CAAA,CAAA,EA6MxB,GA7MwB,CAAA,MAAA,EA6MZ,UA7MY,CAAA"}
@@ -0,0 +1,40 @@
1
+ import { Journal } from "./journal.js";
2
+ import { MetricsRegistry } from "./metrics.js";
3
+ import { Mountable } from "./types.js";
4
+ import { MCPContent, MCPMockOptions, MCPPromptDefinition, MCPPromptResult, MCPResourceContent, MCPResourceDefinition, MCPSession, MCPToolDefinition } from "./mcp-types.js";
5
+ import * as http from "node:http";
6
+
7
+ //#region src/mcp-mock.d.ts
8
+ declare class MCPMock implements Mountable {
9
+ private tools;
10
+ private resources;
11
+ private prompts;
12
+ private sessions;
13
+ private server;
14
+ private journal;
15
+ private registry;
16
+ private options;
17
+ private requestHandler;
18
+ constructor(options?: MCPMockOptions);
19
+ addTool(def: MCPToolDefinition): this;
20
+ onToolCall(name: string, handler: (args: unknown) => MCPContent[] | string | Promise<MCPContent[] | string>): this;
21
+ addResource(def: MCPResourceDefinition, content?: MCPResourceContent): this;
22
+ addPrompt(def: MCPPromptDefinition, handler?: (args: unknown) => MCPPromptResult | Promise<MCPPromptResult>): this;
23
+ handleRequest(req: http.IncomingMessage, res: http.ServerResponse, pathname: string): Promise<boolean>;
24
+ health(): {
25
+ status: string;
26
+ [key: string]: unknown;
27
+ };
28
+ setJournal(journal: Journal): void;
29
+ setRegistry(registry: MetricsRegistry): void;
30
+ start(): Promise<string>;
31
+ stop(): Promise<void>;
32
+ getRequests(): unknown[];
33
+ getSessions(): Map<string, MCPSession>;
34
+ reset(): this;
35
+ private buildHandler;
36
+ }
37
+ //# sourceMappingURL=mcp-mock.d.ts.map
38
+ //#endregion
39
+ export { MCPMock };
40
+ //# sourceMappingURL=mcp-mock.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-mock.d.ts","names":[],"sources":["../src/mcp-mock.ts"],"sourcesContent":[],"mappings":";;;;;;;cAiBa,OAAA,YAAmB;;EAAnB,QAAA,SAAQ;EAAA,QAAA,OAAA;UAqBG,QAAA;UAOT,MAAA;UAOiB,OAAA;UAAgC,QAAA;UAAR,OAAA;UAarC,cAAA;aAAiC,CAAA,OAAA,CAAA,EA3B5B,cA2B4B;SAQ3C,CAAA,GAAA,EA5BM,iBA4BN,CAAA,EAAA,IAAA;YACwB,CAAA,IAAA,EAAA,MAAA,EAAA,OAAA,EAAA,CAAA,IAAA,EAAA,OAAA,EAAA,GAtBD,UAsBC,EAAA,GAAA,MAAA,GAtBuB,OAsBvB,CAtB+B,UAsB/B,EAAA,GAAA,MAAA,CAAA,CAAA,EAAA,IAAA;aAA0B,CAAA,GAAA,EATxC,qBASwC,EAAA,OAAA,CAAA,EATP,kBASO,CAAA,EAAA,IAAA;WAAR,CAAA,GAAA,EAD1C,mBAC0C,EAAA,OAAA,CAAA,EAAA,CAAA,IAAA,EAAA,OAAA,EAAA,GAAlB,eAAkB,GAAA,OAAA,CAAQ,eAAR,CAAA,CAAA,EAAA,IAAA;eASrC,CAAA,GAAA,EAAL,IAAA,CAAK,eAAA,EAAA,GAAA,EACL,IAAA,CAAK,cADA,EAAA,QAAA,EAAA,MAAA,CAAA,EAGT,OAHS,CAAA,OAAA,CAAA;QACL,CAAA,CAAK,EAAA;IAET,MAAA,EAAA,MAAA;IAwDiB,CAAA,GAAA,EAAA,MAAA,CAAA,EAAA,OAAA;;YAUL,CAAA,OAAA,EAVK,OAUL,CAAA,EAAA,IAAA;aAoDD,CAAA,QAAA,EA1DQ,eA0DR,CAAA,EAAA,IAAA;OAkBa,CAAA,CAAA,EAtEZ,OAsEY,CAAA,MAAA,CAAA;MAAZ,CAAA,CAAA,EAlBD,OAkBC,CAAA,IAAA,CAAA;aA7Me,CAAA,CAAA,EAAA,OAAA,EAAA;EAAS,WAAA,CAAA,CAAA,EA6MxB,GA7MwB,CAAA,MAAA,EA6MZ,UA7MY,CAAA"}
@@ -0,0 +1,167 @@
1
+ import { flattenHeaders, readBody } from "./helpers.js";
2
+ import { createMCPRequestHandler } from "./mcp-handler.js";
3
+ import * as http from "node:http";
4
+
5
+ //#region src/mcp-mock.ts
6
+ var MCPMock = class {
7
+ tools = /* @__PURE__ */ new Map();
8
+ resources = /* @__PURE__ */ new Map();
9
+ prompts = /* @__PURE__ */ new Map();
10
+ sessions = /* @__PURE__ */ new Map();
11
+ server = null;
12
+ journal = null;
13
+ registry = null;
14
+ options;
15
+ requestHandler;
16
+ constructor(options) {
17
+ this.options = options ?? {};
18
+ this.requestHandler = this.buildHandler();
19
+ }
20
+ addTool(def) {
21
+ this.tools.set(def.name, { def });
22
+ return this;
23
+ }
24
+ onToolCall(name, handler) {
25
+ const entry = this.tools.get(name);
26
+ if (entry) entry.handler = handler;
27
+ else this.tools.set(name, {
28
+ def: { name },
29
+ handler
30
+ });
31
+ return this;
32
+ }
33
+ addResource(def, content) {
34
+ this.resources.set(def.uri, {
35
+ def,
36
+ content
37
+ });
38
+ return this;
39
+ }
40
+ addPrompt(def, handler) {
41
+ this.prompts.set(def.name, {
42
+ def,
43
+ handler
44
+ });
45
+ return this;
46
+ }
47
+ async handleRequest(req, res, pathname) {
48
+ if (pathname !== "/" && pathname !== "") return false;
49
+ if (req.method !== "POST" && req.method !== "DELETE") return false;
50
+ const body = await readBody(req);
51
+ if (this.registry) if (req.method === "DELETE") this.registry.incrementCounter("aimock_mcp_requests_total", { method: "session/delete" });
52
+ else try {
53
+ const parsed = JSON.parse(body);
54
+ const method = typeof parsed === "object" && parsed !== null && "method" in parsed ? String(parsed.method) : "unknown";
55
+ this.registry.incrementCounter("aimock_mcp_requests_total", { method });
56
+ } catch {
57
+ this.registry.incrementCounter("aimock_mcp_requests_total", { method: "unknown" });
58
+ }
59
+ await this.requestHandler(req, res, body);
60
+ if (this.journal) this.journal.add({
61
+ method: req.method ?? "POST",
62
+ path: req.url ?? "/",
63
+ headers: flattenHeaders(req.headers),
64
+ body: null,
65
+ service: "mcp",
66
+ response: {
67
+ status: res.statusCode,
68
+ fixture: null
69
+ }
70
+ });
71
+ return true;
72
+ }
73
+ health() {
74
+ return {
75
+ status: "ok",
76
+ tools: this.tools.size,
77
+ resources: this.resources.size,
78
+ prompts: this.prompts.size,
79
+ sessions: this.sessions.size
80
+ };
81
+ }
82
+ setJournal(journal) {
83
+ this.journal = journal;
84
+ }
85
+ setRegistry(registry) {
86
+ this.registry = registry;
87
+ }
88
+ async start() {
89
+ if (this.server) throw new Error("Server already started");
90
+ const host = this.options.host ?? "127.0.0.1";
91
+ const port = this.options.port ?? 0;
92
+ return new Promise((resolve, reject) => {
93
+ const srv = http.createServer((req, res) => {
94
+ const chunks = [];
95
+ req.on("data", (chunk) => chunks.push(chunk));
96
+ req.on("end", () => {
97
+ const body = Buffer.concat(chunks).toString();
98
+ this.requestHandler(req, res, body).then(() => {
99
+ if (this.journal) this.journal.add({
100
+ method: req.method ?? "POST",
101
+ path: req.url ?? "/",
102
+ headers: flattenHeaders(req.headers),
103
+ body: null,
104
+ service: "mcp",
105
+ response: {
106
+ status: res.statusCode,
107
+ fixture: null
108
+ }
109
+ });
110
+ }).catch((err) => {
111
+ console.error("MCPMock request error:", err);
112
+ if (!res.headersSent) {
113
+ res.writeHead(500);
114
+ res.end("Internal server error");
115
+ }
116
+ });
117
+ });
118
+ });
119
+ srv.listen(port, host, () => {
120
+ this.server = srv;
121
+ const addr = srv.address();
122
+ if (typeof addr === "object" && addr !== null) resolve(`http://${host}:${addr.port}`);
123
+ else resolve(`http://${host}:${port}`);
124
+ });
125
+ srv.on("error", reject);
126
+ });
127
+ }
128
+ async stop() {
129
+ if (!this.server) throw new Error("Server not started");
130
+ const srv = this.server;
131
+ this.server = null;
132
+ await new Promise((resolve, reject) => {
133
+ srv.close((err) => err ? reject(err) : resolve());
134
+ });
135
+ }
136
+ getRequests() {
137
+ if (!this.journal) return [];
138
+ return this.journal.getAll().filter((e) => e.service === "mcp");
139
+ }
140
+ getSessions() {
141
+ return new Map(this.sessions);
142
+ }
143
+ reset() {
144
+ this.tools.clear();
145
+ this.resources.clear();
146
+ this.prompts.clear();
147
+ this.sessions.clear();
148
+ this.requestHandler = this.buildHandler();
149
+ return this;
150
+ }
151
+ buildHandler() {
152
+ return createMCPRequestHandler({
153
+ serverInfo: this.options.serverInfo ?? {
154
+ name: "mcp-mock",
155
+ version: "1.0.0"
156
+ },
157
+ tools: this.tools,
158
+ resources: this.resources,
159
+ prompts: this.prompts,
160
+ sessions: this.sessions
161
+ });
162
+ }
163
+ };
164
+
165
+ //#endregion
166
+ export { MCPMock };
167
+ //# sourceMappingURL=mcp-mock.js.map