@novorb/mcp-core 2.1.1 → 3.0.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 (240) hide show
  1. package/README.md +82 -161
  2. package/bin/mcp-core-jest.mjs +112 -0
  3. package/dist/auth.d.ts +57 -0
  4. package/dist/auth.d.ts.map +1 -0
  5. package/dist/auth.js +74 -0
  6. package/dist/auth.js.map +1 -0
  7. package/dist/bootstrap.d.ts +129 -0
  8. package/dist/bootstrap.d.ts.map +1 -0
  9. package/dist/bootstrap.js +206 -0
  10. package/dist/bootstrap.js.map +1 -0
  11. package/dist/client-input.d.ts +72 -0
  12. package/dist/client-input.d.ts.map +1 -0
  13. package/dist/client-input.js +109 -0
  14. package/dist/client-input.js.map +1 -0
  15. package/dist/credential-checks.d.ts +80 -0
  16. package/dist/credential-checks.d.ts.map +1 -0
  17. package/dist/credential-checks.js +189 -0
  18. package/dist/credential-checks.js.map +1 -0
  19. package/dist/credential-health.d.ts +12 -0
  20. package/dist/credential-health.d.ts.map +1 -0
  21. package/dist/credential-health.js +12 -0
  22. package/dist/credential-health.js.map +1 -0
  23. package/dist/credential-report.d.ts +46 -0
  24. package/dist/credential-report.d.ts.map +1 -0
  25. package/dist/credential-report.js +135 -0
  26. package/dist/credential-report.js.map +1 -0
  27. package/dist/credential-status-tool.d.ts +20 -0
  28. package/dist/credential-status-tool.d.ts.map +1 -0
  29. package/dist/credential-status-tool.js +33 -0
  30. package/dist/credential-status-tool.js.map +1 -0
  31. package/dist/credentials.d.ts +288 -0
  32. package/dist/credentials.d.ts.map +1 -0
  33. package/dist/credentials.js +652 -0
  34. package/dist/credentials.js.map +1 -0
  35. package/dist/express-peers.d.ts +29 -0
  36. package/dist/express-peers.d.ts.map +1 -0
  37. package/dist/express-peers.js +36 -0
  38. package/dist/express-peers.js.map +1 -0
  39. package/dist/express.d.ts +74 -0
  40. package/dist/express.d.ts.map +1 -0
  41. package/dist/express.js +164 -0
  42. package/dist/express.js.map +1 -0
  43. package/dist/http-client.d.ts +278 -43
  44. package/dist/http-client.d.ts.map +1 -1
  45. package/dist/http-client.js +620 -182
  46. package/dist/http-client.js.map +1 -1
  47. package/dist/index.d.ts +27 -6
  48. package/dist/index.d.ts.map +1 -1
  49. package/dist/index.js +49 -10
  50. package/dist/index.js.map +1 -1
  51. package/dist/limits.d.ts +28 -0
  52. package/dist/limits.d.ts.map +1 -0
  53. package/dist/limits.js +37 -0
  54. package/dist/limits.js.map +1 -0
  55. package/dist/list-pagination.d.ts +41 -0
  56. package/dist/list-pagination.d.ts.map +1 -0
  57. package/dist/list-pagination.js +104 -0
  58. package/dist/list-pagination.js.map +1 -0
  59. package/dist/net.d.ts +112 -0
  60. package/dist/net.d.ts.map +1 -0
  61. package/dist/net.js +490 -0
  62. package/dist/net.js.map +1 -0
  63. package/dist/notifications.d.ts +78 -0
  64. package/dist/notifications.d.ts.map +1 -0
  65. package/dist/notifications.js +173 -0
  66. package/dist/notifications.js.map +1 -0
  67. package/dist/pagination.d.ts +236 -5
  68. package/dist/pagination.d.ts.map +1 -1
  69. package/dist/pagination.js +393 -6
  70. package/dist/pagination.js.map +1 -1
  71. package/dist/prompts.d.ts +70 -0
  72. package/dist/prompts.d.ts.map +1 -0
  73. package/dist/prompts.js +109 -0
  74. package/dist/prompts.js.map +1 -0
  75. package/dist/protocol-errors.d.ts +15 -0
  76. package/dist/protocol-errors.d.ts.map +1 -0
  77. package/dist/protocol-errors.js +28 -0
  78. package/dist/protocol-errors.js.map +1 -0
  79. package/dist/protocol-logging.d.ts +37 -0
  80. package/dist/protocol-logging.d.ts.map +1 -0
  81. package/dist/protocol-logging.js +77 -0
  82. package/dist/protocol-logging.js.map +1 -0
  83. package/dist/rate-limiter.d.ts +36 -0
  84. package/dist/rate-limiter.d.ts.map +1 -0
  85. package/dist/rate-limiter.js +79 -0
  86. package/dist/rate-limiter.js.map +1 -0
  87. package/dist/request-state.d.ts +74 -0
  88. package/dist/request-state.d.ts.map +1 -0
  89. package/dist/request-state.js +190 -0
  90. package/dist/request-state.js.map +1 -0
  91. package/dist/resources.d.ts +181 -0
  92. package/dist/resources.d.ts.map +1 -0
  93. package/dist/resources.js +302 -0
  94. package/dist/resources.js.map +1 -0
  95. package/dist/result-limits.d.ts +80 -0
  96. package/dist/result-limits.d.ts.map +1 -0
  97. package/dist/result-limits.js +248 -0
  98. package/dist/result-limits.js.map +1 -0
  99. package/dist/retry.d.ts +79 -23
  100. package/dist/retry.d.ts.map +1 -1
  101. package/dist/retry.js +170 -57
  102. package/dist/retry.js.map +1 -1
  103. package/dist/sdk/client-stdio.d.ts +6 -0
  104. package/dist/sdk/client-stdio.d.ts.map +1 -0
  105. package/dist/sdk/client-stdio.js +6 -0
  106. package/dist/sdk/client-stdio.js.map +1 -0
  107. package/dist/sdk/client.d.ts +6 -0
  108. package/dist/sdk/client.d.ts.map +1 -0
  109. package/dist/sdk/client.js +6 -0
  110. package/dist/sdk/client.js.map +1 -0
  111. package/dist/sdk/express.d.ts +3 -0
  112. package/dist/sdk/express.d.ts.map +1 -0
  113. package/dist/sdk/express.js +11 -0
  114. package/dist/sdk/express.js.map +1 -0
  115. package/dist/sdk/node.d.ts +6 -0
  116. package/dist/sdk/node.d.ts.map +1 -0
  117. package/dist/sdk/node.js +6 -0
  118. package/dist/sdk/node.js.map +1 -0
  119. package/dist/sdk/server-stdio.d.ts +6 -0
  120. package/dist/sdk/server-stdio.d.ts.map +1 -0
  121. package/dist/sdk/server-stdio.js +6 -0
  122. package/dist/sdk/server-stdio.js.map +1 -0
  123. package/dist/sdk/server.d.ts +6 -0
  124. package/dist/sdk/server.d.ts.map +1 -0
  125. package/dist/sdk/server.js +6 -0
  126. package/dist/sdk/server.js.map +1 -0
  127. package/dist/server.d.ts +88 -36
  128. package/dist/server.d.ts.map +1 -1
  129. package/dist/server.js +98 -44
  130. package/dist/server.js.map +1 -1
  131. package/dist/task-request.d.ts +20 -0
  132. package/dist/task-request.d.ts.map +1 -0
  133. package/dist/task-request.js +43 -0
  134. package/dist/task-request.js.map +1 -0
  135. package/dist/task-store.d.ts +230 -0
  136. package/dist/task-store.d.ts.map +1 -0
  137. package/dist/task-store.js +459 -0
  138. package/dist/task-store.js.map +1 -0
  139. package/dist/task-tools.d.ts +115 -0
  140. package/dist/task-tools.d.ts.map +1 -0
  141. package/dist/task-tools.js +397 -0
  142. package/dist/task-tools.js.map +1 -0
  143. package/dist/testing/client.d.ts +25 -0
  144. package/dist/testing/client.d.ts.map +1 -0
  145. package/dist/testing/client.js +11 -0
  146. package/dist/testing/client.js.map +1 -0
  147. package/dist/testing/in-memory.d.ts +26 -0
  148. package/dist/testing/in-memory.d.ts.map +1 -0
  149. package/dist/testing/in-memory.js +41 -0
  150. package/dist/testing/in-memory.js.map +1 -0
  151. package/dist/testing/index.d.ts +20 -0
  152. package/dist/testing/index.d.ts.map +1 -0
  153. package/dist/testing/index.js +20 -0
  154. package/dist/testing/index.js.map +1 -0
  155. package/dist/testing/isolated-dirs.d.ts +27 -0
  156. package/dist/testing/isolated-dirs.d.ts.map +1 -0
  157. package/dist/testing/isolated-dirs.js +67 -0
  158. package/dist/testing/isolated-dirs.js.map +1 -0
  159. package/dist/testing/logs.d.ts +61 -0
  160. package/dist/testing/logs.d.ts.map +1 -0
  161. package/dist/testing/logs.js +113 -0
  162. package/dist/testing/logs.js.map +1 -0
  163. package/dist/testing/raw-http.d.ts +25 -0
  164. package/dist/testing/raw-http.d.ts.map +1 -0
  165. package/dist/testing/raw-http.js +41 -0
  166. package/dist/testing/raw-http.js.map +1 -0
  167. package/dist/testing/raw-peer.d.ts +43 -0
  168. package/dist/testing/raw-peer.d.ts.map +1 -0
  169. package/dist/testing/raw-peer.js +101 -0
  170. package/dist/testing/raw-peer.js.map +1 -0
  171. package/dist/testing/recording-server.d.ts +38 -0
  172. package/dist/testing/recording-server.d.ts.map +1 -0
  173. package/dist/testing/recording-server.js +38 -0
  174. package/dist/testing/recording-server.js.map +1 -0
  175. package/dist/testing/server-process.d.ts +76 -0
  176. package/dist/testing/server-process.d.ts.map +1 -0
  177. package/dist/testing/server-process.js +241 -0
  178. package/dist/testing/server-process.js.map +1 -0
  179. package/dist/testing/tools.d.ts +53 -0
  180. package/dist/testing/tools.d.ts.map +1 -0
  181. package/dist/testing/tools.js +98 -0
  182. package/dist/testing/tools.js.map +1 -0
  183. package/dist/testing/unit.d.ts +52 -0
  184. package/dist/testing/unit.d.ts.map +1 -0
  185. package/dist/testing/unit.js +95 -0
  186. package/dist/testing/unit.js.map +1 -0
  187. package/dist/tools.d.ts +205 -0
  188. package/dist/tools.d.ts.map +1 -0
  189. package/dist/tools.js +370 -0
  190. package/dist/tools.js.map +1 -0
  191. package/dist/transport.d.ts +144 -53
  192. package/dist/transport.d.ts.map +1 -1
  193. package/dist/transport.js +305 -122
  194. package/dist/transport.js.map +1 -1
  195. package/dist/url-path.d.ts +49 -0
  196. package/dist/url-path.d.ts.map +1 -0
  197. package/dist/url-path.js +165 -0
  198. package/dist/url-path.js.map +1 -0
  199. package/dist/utils/dataStore.d.ts +143 -0
  200. package/dist/utils/dataStore.d.ts.map +1 -0
  201. package/dist/utils/dataStore.js +429 -0
  202. package/dist/utils/dataStore.js.map +1 -0
  203. package/dist/utils/envLoader.d.ts +129 -0
  204. package/dist/utils/envLoader.d.ts.map +1 -0
  205. package/dist/utils/envLoader.js +399 -0
  206. package/dist/utils/envLoader.js.map +1 -0
  207. package/dist/utils/logger.d.ts +181 -0
  208. package/dist/utils/logger.d.ts.map +1 -0
  209. package/dist/utils/logger.js +664 -0
  210. package/dist/utils/logger.js.map +1 -0
  211. package/dist/utils/redact.d.ts +50 -0
  212. package/dist/utils/redact.d.ts.map +1 -0
  213. package/dist/utils/redact.js +318 -0
  214. package/dist/utils/redact.js.map +1 -0
  215. package/docs/api-reference.md +29 -0
  216. package/docs/building-a-server.md +63 -0
  217. package/docs/credentials.md +131 -0
  218. package/docs/data-store.md +37 -0
  219. package/docs/env.md +38 -0
  220. package/docs/features.md +28 -0
  221. package/docs/http-client.md +116 -0
  222. package/docs/logger.md +100 -0
  223. package/docs/migrating-to-v3.md +45 -0
  224. package/docs/outbound-urls.md +104 -0
  225. package/docs/pagination.md +45 -0
  226. package/docs/protocol-features.md +62 -0
  227. package/docs/resources-prompts-tasks.md +95 -0
  228. package/docs/sdk.md +33 -0
  229. package/docs/server.md +68 -0
  230. package/docs/testing-harness.md +139 -0
  231. package/docs/testing.md +151 -0
  232. package/docs/tools.md +88 -0
  233. package/docs/transport.md +85 -0
  234. package/examples/testing/tools.integration.test.example.ts +312 -0
  235. package/examples/testing/tools.unit.test.example.ts +149 -0
  236. package/package.json +140 -18
  237. package/dist/logger.d.ts +0 -80
  238. package/dist/logger.d.ts.map +0 -1
  239. package/dist/logger.js +0 -236
  240. package/dist/logger.js.map +0 -1
@@ -0,0 +1,397 @@
1
+ /**
2
+ * @novorb/mcp-core - Task tools (long-running tools on MCP Tasks, both protocol eras)
3
+ *
4
+ * A task tool answers a task handle instead of blocking: the client polls (or, on 2025-11-25, waits
5
+ * on `tasks/result`) and can cancel. The work runs in this process behind a `ManagedTaskStore`; the
6
+ * SDK 2.3.1 ships the wire types only, so mcp-core serves the methods itself, per era, with the
7
+ * shapes of the spec and of SDK PR #2782:
8
+ *
9
+ * | | 2025-11-25 (legacy) | 2026-07-28 (modern, `io.modelcontextprotocol/tasks` extension) |
10
+ * |---|---|---|
11
+ * | capability | `tasks: { list, cancel, requests: { tools: { call } } }` | `extensions: { 'io.modelcontextprotocol/tasks': {} }` |
12
+ * | start | `tools/call` with `params.task: { ttl? }` -> `{ task, content }` | `tools/call` from a client declaring the extension -> `{ resultType: 'task', ...task }` |
13
+ * | poll | `tasks/get` -> Task (`ttl`, `pollInterval`) | `tasks/get` -> DetailedTask (result / error / inputRequests inlined) |
14
+ * | result | `tasks/result` (blocks until terminal) | inlined in `tasks/get` |
15
+ * | list | `tasks/list` | none (not in the extension) |
16
+ * | cancel | `tasks/cancel` -> Task (terminal = -32602) | `tasks/cancel` -> ack (idempotent) |
17
+ * | input | not supported (no `tasks/result` side channel) | `tasks/update` answers `input_required` |
18
+ * | status | `notifications/tasks/status` (stdio: the connection is long-lived) | polling only (the extension has no notifications yet) |
19
+ *
20
+ * A client without task support (no `params.task`, no declared extension) gets the tool run
21
+ * synchronously: the same `run` with progress notifications, unless `taskSupport: 'required'`.
22
+ * Tasks are bound to the creating caller's `clientId`.
23
+ *
24
+ * registerTaskTools(server, [
25
+ * defineTaskTool({
26
+ * name: 'export_report', description: 'Export a report', inputSchema: z.object({ report: z.string() }),
27
+ * annotations: TOOL_ANNOTATIONS.mutableWriteOpenWorld,
28
+ * run: async ({ report }, task) => {
29
+ * for (let i = 1; i <= 10; i++) { task.signal.throwIfAborted(); await step(); await task.progress(i, 10); }
30
+ * return toolResult({ report, rows: 42 });
31
+ * },
32
+ * }),
33
+ * ], { store, request: req, env });
34
+ */
35
+ import { CLIENT_CAPABILITIES_META_KEY, isInputRequiredResult, MissingRequiredClientCapabilityError, ProtocolError, ProtocolErrorCode, RELATED_TASK_META_KEY, } from '@modelcontextprotocol/server';
36
+ import { requestEra } from './client-input.js';
37
+ import { resolveLimits } from './limits.js';
38
+ import { InvalidCursorError } from './pagination.js';
39
+ import { currentTaskAugmentation } from './task-request.js';
40
+ import { isTerminalStatus, TASKS_EXTENSION_ID, } from './task-store.js';
41
+ import { defaultMapError, defineTool, maskClientText, normalizeOutcome, registerTools, toolError, } from './tools.js';
42
+ import { getLogger } from './utils/logger.js';
43
+ /** Identity helper that types `run` from the tool's own input schema. */
44
+ export function defineTaskTool(definition) {
45
+ return definition;
46
+ }
47
+ const DEFAULT_TTL_MS = 3_600_000;
48
+ const DEFAULT_POLL_MS = 1000;
49
+ /** Map a task onto the 2025-11-25 wire shape. */
50
+ export function toLegacyTask(task) {
51
+ return {
52
+ taskId: task.taskId,
53
+ status: task.status,
54
+ ttl: task.ttlMs,
55
+ createdAt: task.createdAt,
56
+ lastUpdatedAt: task.lastUpdatedAt,
57
+ ...(task.pollIntervalMs !== undefined ? { pollInterval: task.pollIntervalMs } : {}),
58
+ ...(task.statusMessage !== undefined ? { statusMessage: task.statusMessage } : {}),
59
+ };
60
+ }
61
+ function isRecord(value) {
62
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
63
+ }
64
+ /** Whether a 2026-07-28 request declared the tasks extension in its envelope capabilities. */
65
+ export function declaresTasksExtension(sdk) {
66
+ const envelope = sdk.mcpReq.envelope;
67
+ const caps = envelope?.[CLIENT_CAPABILITIES_META_KEY];
68
+ return isRecord(caps) && isRecord(caps.extensions) && TASKS_EXTENSION_ID in caps.extensions;
69
+ }
70
+ function requireExtension(sdk, what) {
71
+ if (declaresTasksExtension(sdk))
72
+ return;
73
+ throw new MissingRequiredClientCapabilityError({ requiredCapabilities: { extensions: { [TASKS_EXTENSION_ID]: {} } } }, `${what} requires the request to declare the "${TASKS_EXTENSION_ID}" extension capability`);
74
+ }
75
+ function accessOf(sdk) {
76
+ const principal = sdk.http?.authInfo?.clientId;
77
+ return principal !== undefined ? { principal } : {};
78
+ }
79
+ const notFound = () => new ProtocolError(ProtocolErrorCode.InvalidParams, 'Task not found');
80
+ /** A minimal Standard Schema over a hand-written check (src/ never loads zod). */
81
+ function paramsSchema(parse) {
82
+ return {
83
+ '~standard': {
84
+ version: 1,
85
+ vendor: 'mcp-core',
86
+ validate: (value) => {
87
+ if (!isRecord(value))
88
+ return { issues: [{ message: 'params must be an object' }] };
89
+ try {
90
+ return { value: parse(value) };
91
+ }
92
+ catch (e) {
93
+ return { issues: [{ message: e instanceof Error ? e.message : 'invalid params' }] };
94
+ }
95
+ },
96
+ },
97
+ };
98
+ }
99
+ const taskIdParams = paramsSchema((p) => {
100
+ if (typeof p.taskId !== 'string' || p.taskId === '')
101
+ throw new Error('taskId must be a non-empty string');
102
+ return {
103
+ taskId: p.taskId,
104
+ inputResponses: isRecord(p.inputResponses) ? p.inputResponses : undefined,
105
+ };
106
+ });
107
+ const listParams = paramsSchema((p) => {
108
+ if (p.cursor !== undefined && typeof p.cursor !== 'string')
109
+ throw new Error('cursor must be a string');
110
+ return { cursor: p.cursor };
111
+ });
112
+ async function waitForTerminal(store, taskId, access, signal, pollMs) {
113
+ for (;;) {
114
+ const task = await store.get(taskId, access);
115
+ if (!task)
116
+ throw notFound();
117
+ if (isTerminalStatus(task.status))
118
+ return task;
119
+ await new Promise((resolve, reject) => {
120
+ const done = () => {
121
+ clearTimeout(timer);
122
+ unwatch();
123
+ signal.removeEventListener('abort', onAbort);
124
+ };
125
+ const onAbort = () => {
126
+ done();
127
+ reject(signal.reason);
128
+ };
129
+ // Woken by this process's writes; the timer covers writes from other processes (file store).
130
+ const unwatch = store.watch(taskId, () => {
131
+ done();
132
+ resolve();
133
+ });
134
+ const timer = setTimeout(() => {
135
+ done();
136
+ resolve();
137
+ }, pollMs);
138
+ if (signal.aborted)
139
+ onAbort();
140
+ else
141
+ signal.addEventListener('abort', onAbort, { once: true });
142
+ });
143
+ }
144
+ }
145
+ const TASKS_INSTALLED = Symbol.for('@novorb/mcp-core/tasks');
146
+ /**
147
+ * Serve the task methods for this instance's era and advertise the matching capability (call before
148
+ * the instance is connected; `registerTaskTools` does it). Idempotent.
149
+ */
150
+ export function enableTasks(server, store, options) {
151
+ const low = server.server;
152
+ if (low[TASKS_INSTALLED])
153
+ return;
154
+ low[TASKS_INSTALLED] = true;
155
+ const pollMs = options.resultPollMs ?? DEFAULT_POLL_MS;
156
+ if (options.era === 'modern') {
157
+ low.registerCapabilities({ extensions: { [TASKS_EXTENSION_ID]: {} } });
158
+ low.setRequestHandler('tasks/get', { params: taskIdParams }, async (params, sdk) => {
159
+ requireExtension(sdk, 'tasks/get');
160
+ const task = await store.get(params.taskId, accessOf(sdk));
161
+ if (!task)
162
+ throw notFound();
163
+ // The inlined result is a 2026-07-28 CallToolResult: it carries its own resultType (SEP-2663).
164
+ if (task.status === 'completed')
165
+ return { ...task, result: { resultType: 'complete', ...task.result } };
166
+ return { ...task };
167
+ });
168
+ low.setRequestHandler('tasks/update', { params: taskIdParams }, async (params, sdk) => {
169
+ requireExtension(sdk, 'tasks/update');
170
+ const responses = (sdk.mcpReq.inputResponses ?? params.inputResponses ?? {});
171
+ if (!(await store.update(params.taskId, responses, accessOf(sdk))))
172
+ throw notFound();
173
+ return {};
174
+ });
175
+ low.setRequestHandler('tasks/cancel', { params: taskIdParams }, async (params, sdk) => {
176
+ requireExtension(sdk, 'tasks/cancel');
177
+ if (!(await store.cancel(params.taskId, accessOf(sdk))))
178
+ throw notFound();
179
+ return {};
180
+ });
181
+ return;
182
+ }
183
+ low.registerCapabilities({ tasks: { list: {}, cancel: {}, requests: { tools: { call: {} } } } });
184
+ low.setRequestHandler('tasks/get', { params: taskIdParams }, async (params, sdk) => {
185
+ const task = await store.get(params.taskId, accessOf(sdk));
186
+ if (!task)
187
+ throw notFound();
188
+ return { ...toLegacyTask(task) };
189
+ });
190
+ low.setRequestHandler('tasks/result', { params: taskIdParams }, async (params, sdk) => {
191
+ const task = await waitForTerminal(store, params.taskId, accessOf(sdk), sdk.mcpReq.signal, pollMs);
192
+ const related = { [RELATED_TASK_META_KEY]: { taskId: task.taskId } };
193
+ if (task.status === 'completed') {
194
+ const result = task.result;
195
+ return { ...result, _meta: { ...(isRecord(result._meta) ? result._meta : {}), ...related } };
196
+ }
197
+ if (task.status === 'failed') {
198
+ const code = typeof task.error.code === 'number' ? task.error.code : ProtocolErrorCode.InternalError;
199
+ const message = typeof task.error.message === 'string' ? task.error.message : 'Task failed';
200
+ throw new ProtocolError(code, message, related);
201
+ }
202
+ throw new ProtocolError(ProtocolErrorCode.InvalidRequest, `Task ${task.taskId} was cancelled`, related);
203
+ });
204
+ low.setRequestHandler('tasks/list', { params: listParams }, async (params, sdk) => {
205
+ try {
206
+ const page = await store.list(accessOf(sdk), params.cursor !== undefined ? { cursor: params.cursor } : {});
207
+ return { tasks: page.tasks.map(toLegacyTask), ...(page.nextCursor ? { nextCursor: page.nextCursor } : {}) };
208
+ }
209
+ catch (e) {
210
+ if (e instanceof InvalidCursorError)
211
+ throw new ProtocolError(ProtocolErrorCode.InvalidParams, e.message);
212
+ throw e;
213
+ }
214
+ });
215
+ low.setRequestHandler('tasks/cancel', { params: taskIdParams }, async (params, sdk) => {
216
+ const access = accessOf(sdk);
217
+ const before = await store.get(params.taskId, access);
218
+ if (!before)
219
+ throw notFound();
220
+ if (isTerminalStatus(before.status)) {
221
+ throw new ProtocolError(ProtocolErrorCode.InvalidParams, `Cannot cancel task ${before.taskId}: it is already ${before.status}`);
222
+ }
223
+ await store.cancel(params.taskId, access);
224
+ const after = await store.get(params.taskId, access);
225
+ return { ...toLegacyTask(after ?? before) };
226
+ });
227
+ }
228
+ function formatProgress(current, total, message) {
229
+ const position = total !== undefined ? `${current}/${total}` : String(current);
230
+ return message ? `${message} (${position})` : position;
231
+ }
232
+ function byteCapped(tool, result, maxBytes) {
233
+ const bytes = Buffer.byteLength(JSON.stringify(result), 'utf8');
234
+ if (bytes <= maxBytes)
235
+ return result;
236
+ return toolError(`${tool}: the task result is ${bytes} bytes, over the ${maxBytes} byte limit per response; narrow the request`);
237
+ }
238
+ function errorText(mapError, err) {
239
+ let mapped;
240
+ try {
241
+ mapped = mapError(err);
242
+ }
243
+ catch {
244
+ mapped = { message: 'Internal error' };
245
+ }
246
+ return mapped.code ? `${mapped.code}: ${mapped.message}` : mapped.message;
247
+ }
248
+ /**
249
+ * Register task tools on `server` (through `registerTools`, so logging, masking, degraded mode and
250
+ * the enabled/prefix/surface options are the same) and enable the era's task methods.
251
+ */
252
+ export function registerTaskTools(server, defs, opts) {
253
+ const { store, request, maxResultBytes, resultPollMs, ...toolOptions } = opts;
254
+ enableTasks(server, store, { era: request.era, ...(resultPollMs !== undefined ? { resultPollMs } : {}) });
255
+ const maxBytes = maxResultBytes ?? resolveLimits().maxResultBytes;
256
+ const mapError = opts.mapError ?? defaultMapError;
257
+ const prefix = opts.prefix ?? '';
258
+ const tools = defs.map((def) => {
259
+ const { run, taskSupport, ttlMs, pollIntervalMs, ...rest } = def;
260
+ const name = `${prefix}${def.name}`;
261
+ const definition = {
262
+ ...rest,
263
+ handler: async (args, ctx) => {
264
+ const sdk = ctx.sdk;
265
+ const era = sdk ? requestEra(sdk) : undefined;
266
+ const augmentation = era === 'legacy' ? currentTaskAugmentation() : undefined;
267
+ const asTask = sdk !== undefined && (era === 'modern' ? declaresTasksExtension(sdk) : augmentation !== undefined);
268
+ if (!asTask) {
269
+ if (taskSupport === 'required') {
270
+ return toolError(`${name} runs only as a task: the client must ${era === 'modern' ? `declare the ${TASKS_EXTENSION_ID} extension` : 'send tools/call with params.task (tasks capability)'}`);
271
+ }
272
+ return run(args, {
273
+ mode: 'sync',
274
+ signal: ctx.signal,
275
+ ...(ctx.authInfo ? { authInfo: ctx.authInfo } : {}),
276
+ logger: ctx.logger,
277
+ progress: (current, total, message) => ctx.progress(current, total, message),
278
+ status: (message) => ctx.progress(0, undefined, message),
279
+ requireInput: () => Promise.reject(new Error('requireInput is only available in task mode')),
280
+ });
281
+ }
282
+ const ttl = Math.min(augmentation?.ttl ?? ttlMs ?? DEFAULT_TTL_MS, ttlMs ?? DEFAULT_TTL_MS);
283
+ const principal = sdk.http?.authInfo?.clientId;
284
+ const task = await store.create({
285
+ ttlMs: ttl,
286
+ pollIntervalMs: pollIntervalMs ?? DEFAULT_POLL_MS,
287
+ ...(principal !== undefined ? { principal } : {}),
288
+ context: { tool: name },
289
+ });
290
+ const handle = store.handle(task.taskId);
291
+ if (era === 'legacy')
292
+ notifyStatus(server, store, task.taskId);
293
+ // Detached: a failing store write while settling the task is logged, never an unhandled rejection.
294
+ execute(name, handle, run, args, era === 'modern', ctx, mapError, maxBytes).catch((err) => {
295
+ getLogger().error(`Task settle failed: ${name}`, 'Tasks', {
296
+ tool: name,
297
+ taskId: task.taskId,
298
+ error: err instanceof Error ? err.message : String(err),
299
+ });
300
+ });
301
+ if (era === 'modern')
302
+ return { resultType: 'task', ...task, content: [] };
303
+ return {
304
+ content: [
305
+ { type: 'text', text: `Task ${task.taskId} started (${name}); poll tasks/get or wait on tasks/result` },
306
+ ],
307
+ task: toLegacyTask(task),
308
+ _meta: { [RELATED_TASK_META_KEY]: { taskId: task.taskId } },
309
+ };
310
+ },
311
+ };
312
+ return defineTool(definition);
313
+ });
314
+ const handles = registerTools(server, tools, { ...toolOptions, limits: { maxBytes } });
315
+ if (request.era === 'legacy') {
316
+ // 2025-11-25 advertises per tool whether `params.task` is accepted (`Tool.execution.taskSupport`).
317
+ for (const def of defs) {
318
+ const handle = handles.get(`${prefix}${def.name}`);
319
+ if (handle)
320
+ handle.execution = { taskSupport: def.taskSupport ?? 'optional' };
321
+ }
322
+ }
323
+ return handles;
324
+ }
325
+ /** 2025-era: push `notifications/tasks/status` on this instance's connection until the task is terminal. */
326
+ function notifyStatus(server, store, taskId) {
327
+ const low = server.server;
328
+ const unwatch = store.watch(taskId, (task) => {
329
+ low
330
+ .notification({ method: 'notifications/tasks/status', params: { ...toLegacyTask(task) } })
331
+ .catch(() => undefined);
332
+ if (isTerminalStatus(task.status))
333
+ unwatch();
334
+ });
335
+ const previous = low.onclose;
336
+ low.onclose = () => {
337
+ unwatch();
338
+ previous?.();
339
+ };
340
+ }
341
+ async function execute(tool, handle, run, args, modern, ctx, mapError, maxBytes) {
342
+ const log = getLogger();
343
+ const started = Date.now();
344
+ log.info(`Task started: ${tool}`, 'Tasks', { tool, taskId: handle.taskId });
345
+ const task = {
346
+ mode: 'task',
347
+ taskId: handle.taskId,
348
+ signal: handle.signal,
349
+ ...(ctx.authInfo ? { authInfo: ctx.authInfo } : {}),
350
+ logger: log,
351
+ progress: (current, total, message) => handle.status(formatProgress(current, total, message)),
352
+ status: (message) => handle.status(message),
353
+ requireInput: (requests) => modern
354
+ ? handle.requireInput(requests)
355
+ : Promise.reject(new Error('requireInput is not supported on 2025-era tasks')),
356
+ };
357
+ let outcome = 'completed';
358
+ try {
359
+ const raw = await run(args, task);
360
+ const result = normalizeOutcome(raw);
361
+ if (isInputRequiredResult(result)) {
362
+ outcome = 'failed';
363
+ await handle.fail({
364
+ code: ProtocolErrorCode.InternalError,
365
+ message: `${tool} returned an input-required result; a task asks for input with task.requireInput`,
366
+ });
367
+ return;
368
+ }
369
+ const masked = result.isError === true
370
+ ? {
371
+ ...result,
372
+ content: result.content.map((b) => (b.type === 'text' ? { ...b, text: maskClientText(b.text) } : b)),
373
+ }
374
+ : result;
375
+ await handle.complete(byteCapped(tool, masked, maxBytes));
376
+ }
377
+ catch (err) {
378
+ if (handle.signal.aborted) {
379
+ outcome = 'cancelled';
380
+ return;
381
+ }
382
+ // A tool failure is a completed task with an isError result (the MCP tool-error model).
383
+ outcome = 'error';
384
+ await handle.complete(toolError(errorText(mapError, err)));
385
+ }
386
+ finally {
387
+ if (handle.signal.aborted)
388
+ outcome = 'cancelled';
389
+ log.info(`Task finished: ${tool}`, 'Tasks', {
390
+ tool,
391
+ taskId: handle.taskId,
392
+ outcome,
393
+ durationMs: Math.round(Date.now() - started),
394
+ });
395
+ }
396
+ }
397
+ //# sourceMappingURL=task-tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"task-tools.js","sourceRoot":"","sources":["../src/task-tools.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * @novorb/mcp-core/testing - client construction shared by every harness entry point.
3
+ */
4
+ import { Client, type ClientOptions } from '@modelcontextprotocol/client';
5
+ /**
6
+ * Protocol era the test client negotiates.
7
+ * - `legacy`: the SDK client default (a 2025-era protocol version).
8
+ * - `modern`: `versionNegotiation: { mode: 'auto' }`, which selects 2026-07-28 when the server supports it.
9
+ */
10
+ export type ProtocolEra = 'legacy' | 'modern';
11
+ /** Options every harness entry point accepts for the v2 client it builds. */
12
+ export interface TestClientOptions {
13
+ /** Protocol era (default `legacy`). Ignored when `clientOptions.versionNegotiation` is set. */
14
+ era?: ProtocolEra;
15
+ /** Client name/version announced to the server (default `mcp-core-testing` / `1.0.0`). */
16
+ clientInfo?: {
17
+ name: string;
18
+ version: string;
19
+ };
20
+ /** Extra SDK client options, merged over the era default. */
21
+ clientOptions?: ClientOptions;
22
+ }
23
+ /** Build a v2 `Client` for the given era. */
24
+ export declare function createTestClient(options?: TestClientOptions): Client;
25
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/testing/client.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,MAAM,EAAE,KAAK,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAE1E;;;;GAIG;AACH,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAE9C,6EAA6E;AAC7E,MAAM,WAAW,iBAAiB;IAChC,+FAA+F;IAC/F,GAAG,CAAC,EAAE,WAAW,CAAC;IAClB,0FAA0F;IAC1F,UAAU,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAC/C,6DAA6D;IAC7D,aAAa,CAAC,EAAE,aAAa,CAAC;CAC/B;AAED,6CAA6C;AAC7C,wBAAgB,gBAAgB,CAAC,OAAO,GAAE,iBAAsB,GAAG,MAAM,CAIxE"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * @novorb/mcp-core/testing - client construction shared by every harness entry point.
3
+ */
4
+ import { Client } from '@modelcontextprotocol/client';
5
+ /** Build a v2 `Client` for the given era. */
6
+ export function createTestClient(options = {}) {
7
+ const info = options.clientInfo ?? { name: 'mcp-core-testing', version: '1.0.0' };
8
+ const eraOptions = options.era === 'modern' ? { versionNegotiation: { mode: 'auto' } } : {};
9
+ return new Client(info, { ...eraOptions, ...options.clientOptions });
10
+ }
11
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/testing/client.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,MAAM,EAAsB,MAAM,8BAA8B,CAAC;AAmB1E,6CAA6C;AAC7C,MAAM,UAAU,gBAAgB,CAAC,UAA6B,EAAE;IAC9D,MAAM,IAAI,GAAG,OAAO,CAAC,UAAU,IAAI,EAAE,IAAI,EAAE,kBAAkB,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;IAClF,MAAM,UAAU,GAAkB,OAAO,CAAC,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,kBAAkB,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAC3G,OAAO,IAAI,MAAM,CAAC,IAAI,EAAE,EAAE,GAAG,UAAU,EAAE,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC,CAAC;AACvE,CAAC"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * @novorb/mcp-core/testing - connect a v2 client to a server factory in-process over the SDK's
3
+ * linked in-memory transport pair (no child process, no socket).
4
+ *
5
+ * The server side is the SDK's `serveStdio` connection owner with the in-memory transport as its wire,
6
+ * so the client's opening message selects the protocol era exactly as it does over real stdio (both
7
+ * the 2025 and the 2026-07-28 era work).
8
+ */
9
+ import { type Client } from '@modelcontextprotocol/client';
10
+ import type { ServerEventBus } from '@modelcontextprotocol/server';
11
+ import { type ServerFactory } from '../transport.js';
12
+ import { type TestClientOptions } from './client.js';
13
+ export interface InMemoryConnection {
14
+ client: Client;
15
+ /** Close the client and the server side. Idempotent; never throws. */
16
+ close(): Promise<void>;
17
+ }
18
+ export interface ConnectInMemoryOptions extends TestClientOptions {
19
+ /** Out-of-band server errors (default: ignored). */
20
+ onServerError?: (error: Error) => void;
21
+ /** The change-event bus the connection's instance forwards (default the process bus), as on stdio. */
22
+ bus?: ServerEventBus;
23
+ }
24
+ /** Link `factory` to a fresh v2 client in memory and connect it. */
25
+ export declare function connectInMemory(factory: ServerFactory, options?: ConnectInMemoryOptions): Promise<InMemoryConnection>;
26
+ //# sourceMappingURL=in-memory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"in-memory.d.ts","sourceRoot":"","sources":["../../src/testing/in-memory.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,KAAK,MAAM,EAAqB,MAAM,8BAA8B,CAAC;AAC9E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAGnE,OAAO,EAAoB,KAAK,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACvE,OAAO,EAAoB,KAAK,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEvE,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,sEAAsE;IACtE,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED,MAAM,WAAW,sBAAuB,SAAQ,iBAAiB;IAC/D,oDAAoD;IACpD,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACvC,sGAAsG;IACtG,GAAG,CAAC,EAAE,cAAc,CAAC;CACtB;AAED,oEAAoE;AACpE,wBAAsB,eAAe,CACnC,OAAO,EAAE,aAAa,EACtB,OAAO,GAAE,sBAA2B,GACnC,OAAO,CAAC,kBAAkB,CAAC,CAwB7B"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * @novorb/mcp-core/testing - connect a v2 client to a server factory in-process over the SDK's
3
+ * linked in-memory transport pair (no child process, no socket).
4
+ *
5
+ * The server side is the SDK's `serveStdio` connection owner with the in-memory transport as its wire,
6
+ * so the client's opening message selects the protocol era exactly as it does over real stdio (both
7
+ * the 2025 and the 2026-07-28 era work).
8
+ */
9
+ import { InMemoryTransport } from '@modelcontextprotocol/client';
10
+ import { serveStdio } from '@modelcontextprotocol/server/stdio';
11
+ import { processBus } from '../notifications.js';
12
+ import { notifyingFactory } from '../transport.js';
13
+ import { createTestClient } from './client.js';
14
+ /** Link `factory` to a fresh v2 client in memory and connect it. */
15
+ export async function connectInMemory(factory, options = {}) {
16
+ const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
17
+ const handle = serveStdio(notifyingFactory(factory, options.bus ?? processBus()), {
18
+ transport: serverTransport,
19
+ onerror: options.onServerError,
20
+ });
21
+ const client = createTestClient(options);
22
+ try {
23
+ await client.connect(clientTransport);
24
+ }
25
+ catch (e) {
26
+ await handle.close().catch(() => undefined);
27
+ throw e;
28
+ }
29
+ let closing;
30
+ return {
31
+ client,
32
+ close: () => {
33
+ closing ??= (async () => {
34
+ await client.close().catch(() => undefined);
35
+ await handle.close().catch(() => undefined);
36
+ })();
37
+ return closing;
38
+ },
39
+ };
40
+ }
41
+ //# sourceMappingURL=in-memory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"in-memory.js","sourceRoot":"","sources":["../../src/testing/in-memory.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAe,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAE9E,OAAO,EAAE,UAAU,EAAE,MAAM,oCAAoC,CAAC;AAChE,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAsB,MAAM,iBAAiB,CAAC;AACvE,OAAO,EAAE,gBAAgB,EAA0B,MAAM,aAAa,CAAC;AAevE,oEAAoE;AACpE,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,OAAsB,EACtB,UAAkC,EAAE;IAEpC,MAAM,CAAC,eAAe,EAAE,eAAe,CAAC,GAAG,iBAAiB,CAAC,gBAAgB,EAAE,CAAC;IAChF,MAAM,MAAM,GAAG,UAAU,CAAC,gBAAgB,CAAC,OAAO,EAAE,OAAO,CAAC,GAAG,IAAI,UAAU,EAAE,CAAC,EAAE;QAChF,SAAS,EAAE,eAAe;QAC1B,OAAO,EAAE,OAAO,CAAC,aAAa;KAC/B,CAAC,CAAC;IACH,MAAM,MAAM,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC;IACzC,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;IACxC,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QAC5C,MAAM,CAAC,CAAC;IACV,CAAC;IACD,IAAI,OAAkC,CAAC;IACvC,OAAO;QACL,MAAM;QACN,KAAK,EAAE,GAAG,EAAE;YACV,OAAO,KAAK,CAAC,KAAK,IAAI,EAAE;gBACtB,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;gBAC5C,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;YAC9C,CAAC,CAAC,EAAE,CAAC;YACL,OAAO,OAAO,CAAC;QACjB,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * @novorb/mcp-core/testing - test harness for MCP servers built on mcp-core.
3
+ *
4
+ * A SEPARATE subpath: no runtime entry point imports it. It needs `@modelcontextprotocol/client`
5
+ * (an optional peer dependency; every consumer has it as a devDependency). Test-runner agnostic:
6
+ * helpers return objects and throw Errors; nothing imports jest or vitest.
7
+ *
8
+ * import { startBuiltServer, createIsolatedDirs, callToolJson } from '@novorb/mcp-core/testing';
9
+ */
10
+ export { createTestClient, type ProtocolEra, type TestClientOptions } from './client.js';
11
+ export { type ConnectInMemoryOptions, connectInMemory, type InMemoryConnection } from './in-memory.js';
12
+ export { createIsolatedDirs, type IsolatedDirs } from './isolated-dirs.js';
13
+ export { collectStrings, findLeaks, type Leak, type LogFiles, logFileName, logLevels, MIN_LEAK_NEEDLE_LENGTH, maskValue, readLogFiles, } from './logs.js';
14
+ export { initializeRequestBody, mcpPostHeaders, type RawHttpOptions, type RawHttpResponse, rawHttp, } from './raw-http.js';
15
+ export { MODERN_PROTOCOL_VERSION, modernMeta, parseRpcBody, type RawPeer, type RawResponse, rawHttpPeer, rawPeer, } from './raw-peer.js';
16
+ export { type CapturedPrompt, type CapturedTool, makeRecordingServer, type RecordedConfig, type RecordedPromptHandler, type RecordedToolHandler, type RecordingServer, type RecordingServerOptions, } from './recording-server.js';
17
+ export { type BuiltServer, freePort, type HarnessMode, killAndWait, minimalOsEnv, type StartBuiltServerOptions, startBuiltServer, } from './server-process.js';
18
+ export { assertToolCoverage, callToolJson, captureToolWire, listToolNames, type ToolCoverage, type ToolJsonResult, type ToolWire, toolCoverage, } from './tools.js';
19
+ export { callToolInMemory, captureToolCall, expectSchemaRejection, expectToolError, expectToolSuccess, expectUnknownTool, INVALID_PARAMS_CODE, type Rejection, type ToolOutcome, withInMemoryClient, } from './unit.js';
20
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/testing/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,gBAAgB,EAAE,KAAK,WAAW,EAAE,KAAK,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACzF,OAAO,EAAE,KAAK,sBAAsB,EAAE,eAAe,EAAE,KAAK,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACvG,OAAO,EAAE,kBAAkB,EAAE,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAC3E,OAAO,EACL,cAAc,EACd,SAAS,EACT,KAAK,IAAI,EACT,KAAK,QAAQ,EACb,WAAW,EACX,SAAS,EACT,sBAAsB,EACtB,SAAS,EACT,YAAY,GACb,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,qBAAqB,EACrB,cAAc,EACd,KAAK,cAAc,EACnB,KAAK,eAAe,EACpB,OAAO,GACR,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,uBAAuB,EACvB,UAAU,EACV,YAAY,EACZ,KAAK,OAAO,EACZ,KAAK,WAAW,EAChB,WAAW,EACX,OAAO,GACR,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,KAAK,cAAc,EACnB,KAAK,YAAY,EACjB,mBAAmB,EACnB,KAAK,cAAc,EACnB,KAAK,qBAAqB,EAC1B,KAAK,mBAAmB,EACxB,KAAK,eAAe,EACpB,KAAK,sBAAsB,GAC5B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,KAAK,WAAW,EAChB,QAAQ,EACR,KAAK,WAAW,EAChB,WAAW,EACX,YAAY,EACZ,KAAK,uBAAuB,EAC5B,gBAAgB,GACjB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,kBAAkB,EAClB,YAAY,EACZ,eAAe,EACf,aAAa,EACb,KAAK,YAAY,EACjB,KAAK,cAAc,EACnB,KAAK,QAAQ,EACb,YAAY,GACb,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,qBAAqB,EACrB,eAAe,EACf,iBAAiB,EACjB,iBAAiB,EACjB,mBAAmB,EACnB,KAAK,SAAS,EACd,KAAK,WAAW,EAChB,kBAAkB,GACnB,MAAM,WAAW,CAAC"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * @novorb/mcp-core/testing - test harness for MCP servers built on mcp-core.
3
+ *
4
+ * A SEPARATE subpath: no runtime entry point imports it. It needs `@modelcontextprotocol/client`
5
+ * (an optional peer dependency; every consumer has it as a devDependency). Test-runner agnostic:
6
+ * helpers return objects and throw Errors; nothing imports jest or vitest.
7
+ *
8
+ * import { startBuiltServer, createIsolatedDirs, callToolJson } from '@novorb/mcp-core/testing';
9
+ */
10
+ export { createTestClient } from './client.js';
11
+ export { connectInMemory } from './in-memory.js';
12
+ export { createIsolatedDirs } from './isolated-dirs.js';
13
+ export { collectStrings, findLeaks, logFileName, logLevels, MIN_LEAK_NEEDLE_LENGTH, maskValue, readLogFiles, } from './logs.js';
14
+ export { initializeRequestBody, mcpPostHeaders, rawHttp, } from './raw-http.js';
15
+ export { MODERN_PROTOCOL_VERSION, modernMeta, parseRpcBody, rawHttpPeer, rawPeer, } from './raw-peer.js';
16
+ export { makeRecordingServer, } from './recording-server.js';
17
+ export { freePort, killAndWait, minimalOsEnv, startBuiltServer, } from './server-process.js';
18
+ export { assertToolCoverage, callToolJson, captureToolWire, listToolNames, toolCoverage, } from './tools.js';
19
+ export { callToolInMemory, captureToolCall, expectSchemaRejection, expectToolError, expectToolSuccess, expectUnknownTool, INVALID_PARAMS_CODE, withInMemoryClient, } from './unit.js';
20
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/testing/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,gBAAgB,EAA4C,MAAM,aAAa,CAAC;AACzF,OAAO,EAA+B,eAAe,EAA2B,MAAM,gBAAgB,CAAC;AACvG,OAAO,EAAE,kBAAkB,EAAqB,MAAM,oBAAoB,CAAC;AAC3E,OAAO,EACL,cAAc,EACd,SAAS,EAGT,WAAW,EACX,SAAS,EACT,sBAAsB,EACtB,SAAS,EACT,YAAY,GACb,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,qBAAqB,EACrB,cAAc,EAGd,OAAO,GACR,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,uBAAuB,EACvB,UAAU,EACV,YAAY,EAGZ,WAAW,EACX,OAAO,GACR,MAAM,eAAe,CAAC;AACvB,OAAO,EAGL,mBAAmB,GAMpB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAEL,QAAQ,EAER,WAAW,EACX,YAAY,EAEZ,gBAAgB,GACjB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,kBAAkB,EAClB,YAAY,EACZ,eAAe,EACf,aAAa,EAIb,YAAY,GACb,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,qBAAqB,EACrB,eAAe,EACf,iBAAiB,EACjB,iBAAiB,EACjB,mBAAmB,EAGnB,kBAAkB,GACnB,MAAM,WAAW,CAAC"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * @novorb/mcp-core/testing - per-run temp directories so a server under test writes nothing into the
3
+ * developer's tree or profile.
4
+ */
5
+ export interface IsolatedDirs {
6
+ /** The temp root holding every other directory. */
7
+ root: string;
8
+ /** Working directory for the child (`cwd`). */
9
+ cwd: string;
10
+ /** Home directory (HOME, USERPROFILE, APPDATA, LOCALAPPDATA, XDG_* point inside it). */
11
+ home: string;
12
+ /** Log directory (LOG_PATH). */
13
+ logs: string;
14
+ /** State directory for the server's cache or state files (pass it under the server's own variable). */
15
+ state: string;
16
+ /** Temp directory (TMPDIR, TEMP, TMP). */
17
+ tmp: string;
18
+ /** Create (if needed) and return `<root>/<name>`, for extra data/db directories. */
19
+ dir(name: string): string;
20
+ /** HOME, USERPROFILE, APPDATA, LOCALAPPDATA, XDG_*, TMPDIR/TEMP/TMP and LOG_PATH for the child env. */
21
+ env(): Record<string, string>;
22
+ /** Remove the whole root (retries on Windows EBUSY/EPERM). Idempotent; never throws. */
23
+ cleanup(): void;
24
+ }
25
+ /** Create a fresh temp root under the OS temp dir with cwd, home, logs, state and tmp inside it. */
26
+ export declare function createIsolatedDirs(prefix?: string): IsolatedDirs;
27
+ //# sourceMappingURL=isolated-dirs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"isolated-dirs.d.ts","sourceRoot":"","sources":["../../src/testing/isolated-dirs.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,MAAM,WAAW,YAAY;IAC3B,mDAAmD;IACnD,IAAI,EAAE,MAAM,CAAC;IACb,+CAA+C;IAC/C,GAAG,EAAE,MAAM,CAAC;IACZ,wFAAwF;IACxF,IAAI,EAAE,MAAM,CAAC;IACb,gCAAgC;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,uGAAuG;IACvG,KAAK,EAAE,MAAM,CAAC;IACd,0CAA0C;IAC1C,GAAG,EAAE,MAAM,CAAC;IACZ,oFAAoF;IACpF,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IAC1B,uGAAuG;IACvG,GAAG,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,wFAAwF;IACxF,OAAO,IAAI,IAAI,CAAC;CACjB;AAQD,oGAAoG;AACpG,wBAAgB,kBAAkB,CAAC,MAAM,SAAW,GAAG,YAAY,CAkDlE"}