@cueai/omni-reader-mcp 1.0.2 → 1.1.1

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 (48) hide show
  1. package/README.md +115 -26
  2. package/dist/artifact-store.d.ts +11 -0
  3. package/dist/artifact-store.js +94 -48
  4. package/dist/cli/agent-config.d.ts +29 -4
  5. package/dist/cli/agent-config.js +910 -107
  6. package/dist/cli/arguments.d.ts +32 -0
  7. package/dist/cli/arguments.js +120 -0
  8. package/dist/cli/doctor.d.ts +42 -1
  9. package/dist/cli/doctor.js +109 -36
  10. package/dist/cli/setup.d.ts +3 -0
  11. package/dist/cli/setup.js +103 -18
  12. package/dist/cli/uninstall.d.ts +6 -0
  13. package/dist/cli/uninstall.js +37 -0
  14. package/dist/constants.d.ts +7 -0
  15. package/dist/constants.js +7 -0
  16. package/dist/cube-client.d.ts +5 -3
  17. package/dist/cube-client.js +16 -11
  18. package/dist/cursor.js +2 -0
  19. package/dist/errors.d.ts +32 -1
  20. package/dist/errors.js +26 -1
  21. package/dist/iiis-client.d.ts +18 -4
  22. package/dist/iiis-client.js +194 -40
  23. package/dist/index.d.ts +3 -0
  24. package/dist/index.js +93 -32
  25. package/dist/multipart-body.js +2 -0
  26. package/dist/onboarding-policy.d.ts +10 -0
  27. package/dist/onboarding-policy.js +58 -0
  28. package/dist/operation-journal.d.ts +50 -1
  29. package/dist/operation-journal.js +473 -114
  30. package/dist/operation-manager.d.ts +75 -0
  31. package/dist/operation-manager.js +1324 -0
  32. package/dist/path-security.d.ts +1 -0
  33. package/dist/path-security.js +26 -6
  34. package/dist/progress.d.ts +6 -1
  35. package/dist/protocol.d.ts +26 -13
  36. package/dist/protocol.js +34 -10
  37. package/dist/remote-client.d.ts +17 -0
  38. package/dist/remote-client.js +233 -0
  39. package/dist/result-contract.d.ts +199 -0
  40. package/dist/result-contract.js +235 -0
  41. package/dist/server.js +21 -4
  42. package/dist/source.d.ts +8 -0
  43. package/dist/source.js +37 -0
  44. package/dist/task-runtime.d.ts +13 -0
  45. package/dist/task-runtime.js +94 -0
  46. package/dist/tools.d.ts +19 -1
  47. package/dist/tools.js +317 -112
  48. package/package.json +3 -3
package/dist/tools.js CHANGED
@@ -1,32 +1,33 @@
1
- import { CallToolRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
1
+ import { createHash } from "node:crypto";
2
+ import { CallToolRequestSchema, CancelTaskRequestSchema, ErrorCode, McpError, } from "@modelcontextprotocol/sdk/types.js";
2
3
  import { createClientRequestId as newClientRequestId, } from "./cube-client.js";
3
4
  import { OmniBridgeError } from "./errors.js";
4
5
  import { openAllowedFile, } from "./path-security.js";
5
6
  import { NOOP_PROGRESS } from "./progress.js";
6
- import { SAFETY_INSTRUCTIONS, discardResultSchema, parseDocumentSchema, readResultSchema, } from "./protocol.js";
7
- function bridgeError(code, message) {
7
+ import { MACHINE_INSTRUCTIONS, cancelParseSchema, discardResultSchema, getParseStatusSchema, parseSchema, readResultSchema, } from "./protocol.js";
8
+ import { discardResultOutputSchema, discardResultToolOutputSchema, parseResultSchema, parseToolOutputSchema, readResultOutputSchema, readResultToolOutputSchema, structuredResult, } from "./result-contract.js";
9
+ import { classifySource } from "./source.js";
10
+ import { TaskRuntime } from "./task-runtime.js";
11
+ function bridgeError(code, message, facts = {}) {
8
12
  return new OmniBridgeError({
9
13
  code,
14
+ failureScope: "bridge",
10
15
  message,
11
- fileUploaded: false,
12
- billed: false,
13
- contentReleased: false,
14
- retryable: false,
16
+ operationCreated: facts.operationCreated ?? false,
17
+ fileUploaded: facts.fileUploaded ?? false,
18
+ parserStarted: facts.parserStarted ?? false,
19
+ billed: facts.billed ?? false,
20
+ contentReleased: facts.contentReleased ?? false,
21
+ retryable: facts.retryable ?? false,
15
22
  });
16
23
  }
17
- function errorResult(error) {
18
- const stable = error instanceof OmniBridgeError
24
+ function stableError(error) {
25
+ return error instanceof OmniBridgeError
19
26
  ? error
20
27
  : bridgeError("BRIDGE_INTERNAL_ERROR", "The local Omni Bridge could not complete the request.");
21
- return {
22
- isError: true,
23
- content: [{ type: "text", text: JSON.stringify(stable.toJSON()) }],
24
- };
25
28
  }
26
- function successResult(value) {
27
- return {
28
- content: [{ type: "text", text: JSON.stringify(value) }],
29
- };
29
+ function failed(error) {
30
+ return { status: "failed", error: stableError(error).toJSON() };
30
31
  }
31
32
  function progressSink(extra) {
32
33
  const progressToken = extra._meta?.progressToken;
@@ -41,41 +42,63 @@ function progressSink(extra) {
41
42
  },
42
43
  };
43
44
  }
44
- function parseSuccess(local) {
45
+ function completedLocalResult(local) {
46
+ const dataHandling = {
47
+ processing_copy: "deleted",
48
+ temporary_data: "deleted",
49
+ delivery_result: "deleted_after_ack",
50
+ original_source: "unchanged",
51
+ remote_content_retained: false,
52
+ };
45
53
  if (local.kind === "inline") {
46
- return successResult({
54
+ return {
55
+ status: "completed",
47
56
  operation_id: local.operationId,
48
- text: local.text,
49
- });
57
+ result: { kind: "inline", text: local.text },
58
+ data_handling: dataHandling,
59
+ };
50
60
  }
51
61
  if (local.nextCursor === undefined) {
52
- throw bridgeError("LOCAL_RESULT_INTEGRITY_FAILED", "The local result artifact cursor is missing.");
53
- }
54
- return successResult({
55
- result_id: local.resultId,
56
- result_bytes: local.resultBytes,
57
- artifact_path: local.artifactPath,
58
- expires_at: local.expiresAt,
59
- preview: local.preview,
60
- next_cursor: local.nextCursor,
61
- });
62
+ throw bridgeError("LOCAL_RESULT_INTEGRITY_FAILED", "The local result artifact cursor is missing.", {
63
+ operationCreated: true,
64
+ fileUploaded: true,
65
+ parserStarted: true,
66
+ contentReleased: true,
67
+ });
68
+ }
69
+ return {
70
+ status: "completed",
71
+ operation_id: local.operationId,
72
+ result: {
73
+ kind: "artifact",
74
+ result_id: local.resultId,
75
+ result_bytes: local.resultBytes,
76
+ expires_at: local.expiresAt,
77
+ preview: local.preview,
78
+ next_cursor: local.nextCursor,
79
+ },
80
+ data_handling: dataHandling,
81
+ local_result_cache: {
82
+ expires_at: local.expiresAt,
83
+ discard_action: "discard_result",
84
+ },
85
+ };
62
86
  }
63
- async function parseDocument(args, extra, dependencies) {
87
+ async function parseLocal(args, clientRequestId, signal, progress, dependencies) {
64
88
  const openFile = dependencies.openFile ?? openAllowedFile;
65
- const opened = await openFile(args.local_path, {
89
+ const opened = await openFile(args.source, {
66
90
  workspace: dependencies.workspace,
67
91
  extraRoots: dependencies.extraRoots,
68
92
  });
69
93
  let primaryError;
70
94
  try {
71
- const clientRequestId = (dependencies.createClientRequestId ?? newClientRequestId)();
72
95
  const granted = await dependencies.cubeClient.createGrant({
73
96
  contentLength: opened.size,
74
97
  contentType: opened.contentType,
75
98
  fileExtension: opened.safeExtension,
76
- noStore: args.no_store,
77
- output: args.output,
78
- }, clientRequestId, extra.signal);
99
+ noStore: true,
100
+ output: "markdown",
101
+ }, clientRequestId, signal);
79
102
  const retention = dependencies.artifactStore.createRetention();
80
103
  const operation = {
81
104
  parseGrant: granted.parseGrant,
@@ -85,12 +108,12 @@ async function parseDocument(args, extra, dependencies) {
85
108
  expiresAt: granted.expiresAt,
86
109
  openedFile: opened,
87
110
  retention,
88
- progress: progressSink(extra),
89
- signal: extra.signal,
111
+ progress,
112
+ signal,
90
113
  };
91
114
  await dependencies.iiisClient.uploadAndWait(operation);
92
115
  const local = retention.result();
93
- const result = parseSuccess(local);
116
+ const result = completedLocalResult(local);
94
117
  await dependencies.iiisClient.ack(operation);
95
118
  return result;
96
119
  }
@@ -104,121 +127,303 @@ async function parseDocument(args, extra, dependencies) {
104
127
  }
105
128
  catch {
106
129
  if (primaryError === undefined) {
107
- throw bridgeError("FILE_CLOSE_FAILED", "The local source file could not be closed safely.");
130
+ throw bridgeError("FILE_CLOSE_FAILED", "The local source file could not be closed safely.", {
131
+ operationCreated: true,
132
+ fileUploaded: true,
133
+ parserStarted: true,
134
+ contentReleased: true,
135
+ });
108
136
  }
109
137
  }
110
138
  }
111
139
  }
112
- function readSuccess(result) {
113
- return successResult({
114
- result_id: result.resultId,
115
- result_bytes: result.resultBytes,
116
- expires_at: result.expiresAt,
117
- text: result.text,
118
- ...(result.nextCursor === undefined ? {} : { next_cursor: result.nextCursor }),
119
- });
140
+ async function parseValue(args, signal, progress, dependencies) {
141
+ try {
142
+ const source = classifySource(args.source);
143
+ const clientRequestId = (dependencies.createClientRequestId ?? newClientRequestId)();
144
+ if (dependencies.operationManager !== undefined) {
145
+ const sourceHash = `sha256:${createHash("sha256")
146
+ .update(source.source, "utf8")
147
+ .digest("hex")}`;
148
+ let sourceFingerprint;
149
+ if (source.kind === "local") {
150
+ const openFile = dependencies.openFile ?? openAllowedFile;
151
+ try {
152
+ const opened = await openFile(source.source, {
153
+ workspace: dependencies.workspace,
154
+ extraRoots: dependencies.extraRoots,
155
+ });
156
+ try {
157
+ sourceFingerprint = opened.sourceFingerprint;
158
+ }
159
+ finally {
160
+ await opened.close();
161
+ }
162
+ }
163
+ catch (error) {
164
+ if (!(error instanceof OmniBridgeError) || error.code !== "FILE_NOT_FOUND") {
165
+ throw error;
166
+ }
167
+ }
168
+ }
169
+ return await dependencies.operationManager.submitResult({
170
+ sourceKind: source.kind,
171
+ sourceFacts: {
172
+ sourceHash,
173
+ ...(sourceFingerprint === undefined ? {} : { sourceFingerprint }),
174
+ },
175
+ clientRequestId,
176
+ signal,
177
+ context: source.kind === "local"
178
+ ? { source: source.source, progress }
179
+ : { source: source.source },
180
+ });
181
+ }
182
+ if (source.kind === "url") {
183
+ if (dependencies.remoteClient === undefined) {
184
+ throw bridgeError("REMOTE_PARSE_UNAVAILABLE", "Remote URL parsing is not available in this Bridge build.", { retryable: true });
185
+ }
186
+ return await dependencies.remoteClient.parse(source.source, clientRequestId, signal);
187
+ }
188
+ return await parseLocal(args, clientRequestId, signal, progress, dependencies);
189
+ }
190
+ catch (error) {
191
+ return failed(error);
192
+ }
120
193
  }
121
- function invalidArgumentsResult() {
122
- return errorResult(bridgeError("INVALID_TOOL_ARGUMENTS", "The Omni tool arguments are invalid."));
194
+ async function callParse(args, extra, dependencies) {
195
+ return structuredResult(parseResultSchema, await parseValue(args, extra.signal, progressSink(extra), dependencies));
123
196
  }
124
- async function dispatchTool(name, rawArguments, extra, dependencies) {
125
- if (name === "parse_document") {
126
- const parsed = parseDocumentSchema.safeParse(rawArguments ?? {});
127
- if (!parsed.success)
128
- return invalidArgumentsResult();
129
- try {
130
- return await parseDocument(parsed.data, extra, dependencies);
197
+ async function statusValue(operationId, waitMs, signal, dependencies) {
198
+ try {
199
+ if (dependencies.statusOperation !== undefined) {
200
+ return await dependencies.statusOperation(operationId, waitMs, signal);
131
201
  }
132
- catch (error) {
133
- return errorResult(error);
202
+ if (dependencies.operationManager !== undefined) {
203
+ try {
204
+ return await dependencies.operationManager.statusResult(operationId, waitMs, signal);
205
+ }
206
+ catch (error) {
207
+ if (!(error instanceof OmniBridgeError) || error.code !== "OPERATION_NOT_FOUND") {
208
+ throw error;
209
+ }
210
+ }
134
211
  }
212
+ if (dependencies.remoteClient !== undefined) {
213
+ return await dependencies.remoteClient.status(operationId, waitMs, signal);
214
+ }
215
+ throw bridgeError("OPERATION_NOT_FOUND", "The requested parse operation is not available.", { operationCreated: true });
135
216
  }
136
- if (name === "read_result") {
137
- const parsed = readResultSchema.safeParse(rawArguments ?? {});
138
- if (!parsed.success)
139
- return invalidArgumentsResult();
140
- try {
141
- return readSuccess(await dependencies.artifactStore.read(parsed.data.result_id, parsed.data.cursor, parsed.data.max_bytes));
217
+ catch (error) {
218
+ return failed(error);
219
+ }
220
+ }
221
+ async function callStatus(operationId, waitMs, extra, dependencies) {
222
+ return structuredResult(parseResultSchema, await statusValue(operationId, waitMs, extra.signal, dependencies));
223
+ }
224
+ async function cancelValue(operationId, signal, dependencies) {
225
+ try {
226
+ if (dependencies.cancelOperation !== undefined) {
227
+ return await dependencies.cancelOperation(operationId, signal);
142
228
  }
143
- catch (error) {
144
- return errorResult(error);
229
+ if (dependencies.operationManager !== undefined) {
230
+ try {
231
+ return await dependencies.operationManager.cancelResult(operationId, signal);
232
+ }
233
+ catch (error) {
234
+ if (!(error instanceof OmniBridgeError) || error.code !== "OPERATION_NOT_FOUND") {
235
+ throw error;
236
+ }
237
+ }
145
238
  }
239
+ if (dependencies.remoteClient !== undefined) {
240
+ return await dependencies.remoteClient.cancel(operationId, signal);
241
+ }
242
+ throw bridgeError("OPERATION_NOT_FOUND", "The requested parse operation is not available.", { operationCreated: true });
243
+ }
244
+ catch (error) {
245
+ return failed(error);
246
+ }
247
+ }
248
+ async function callCancel(operationId, extra, dependencies) {
249
+ return structuredResult(parseResultSchema, await cancelValue(operationId, extra.signal, dependencies));
250
+ }
251
+ async function callReadResult(resultId, cursor, maxBytes, dependencies) {
252
+ try {
253
+ const result = await dependencies.artifactStore.read(resultId, cursor, maxBytes);
254
+ return structuredResult(readResultOutputSchema, {
255
+ status: "completed",
256
+ result: {
257
+ result_id: result.resultId,
258
+ result_bytes: result.resultBytes,
259
+ expires_at: result.expiresAt,
260
+ text: result.text,
261
+ ...(result.nextCursor === undefined ? {} : { next_cursor: result.nextCursor }),
262
+ },
263
+ });
264
+ }
265
+ catch (error) {
266
+ return structuredResult(readResultOutputSchema, failed(error));
267
+ }
268
+ }
269
+ async function callDiscardResult(resultId, dependencies) {
270
+ try {
271
+ return structuredResult(discardResultOutputSchema, {
272
+ status: "completed",
273
+ result_id: resultId,
274
+ discarded: await dependencies.artifactStore.discard(resultId),
275
+ });
276
+ }
277
+ catch (error) {
278
+ return structuredResult(discardResultOutputSchema, failed(error));
279
+ }
280
+ }
281
+ function invalidArgumentsResult(name) {
282
+ const error = failed(bridgeError("INVALID_TOOL_ARGUMENTS", "The Omni tool arguments are invalid."));
283
+ if (name === "read_result")
284
+ return structuredResult(readResultOutputSchema, error);
285
+ if (name === "discard_result")
286
+ return structuredResult(discardResultOutputSchema, error);
287
+ return structuredResult(parseResultSchema, error);
288
+ }
289
+ async function dispatchTool(name, rawArguments, extra, dependencies) {
290
+ if (name === "parse") {
291
+ const parsed = parseSchema.safeParse(rawArguments ?? {});
292
+ return parsed.success
293
+ ? callParse(parsed.data, extra, dependencies)
294
+ : invalidArgumentsResult(name);
295
+ }
296
+ if (name === "get_parse_status") {
297
+ const parsed = getParseStatusSchema.safeParse(rawArguments ?? {});
298
+ return parsed.success
299
+ ? callStatus(parsed.data.operation_id, parsed.data.wait_ms, extra, dependencies)
300
+ : invalidArgumentsResult(name);
301
+ }
302
+ if (name === "cancel_parse") {
303
+ const parsed = cancelParseSchema.safeParse(rawArguments ?? {});
304
+ return parsed.success
305
+ ? callCancel(parsed.data.operation_id, extra, dependencies)
306
+ : invalidArgumentsResult(name);
307
+ }
308
+ if (name === "read_result") {
309
+ const parsed = readResultSchema.safeParse(rawArguments ?? {});
310
+ return parsed.success
311
+ ? callReadResult(parsed.data.result_id, parsed.data.cursor, parsed.data.max_bytes, dependencies)
312
+ : invalidArgumentsResult(name);
146
313
  }
147
314
  if (name === "discard_result") {
148
315
  const parsed = discardResultSchema.safeParse(rawArguments ?? {});
149
- if (!parsed.success)
150
- return invalidArgumentsResult();
151
- try {
152
- return successResult({
153
- result_id: parsed.data.result_id,
154
- discarded: await dependencies.artifactStore.discard(parsed.data.result_id),
155
- });
156
- }
157
- catch (error) {
158
- return errorResult(error);
159
- }
316
+ return parsed.success
317
+ ? callDiscardResult(parsed.data.result_id, dependencies)
318
+ : invalidArgumentsResult(name);
160
319
  }
161
- return errorResult(bridgeError("TOOL_NOT_FOUND", "The requested Omni tool is not available."));
320
+ return structuredResult(parseResultSchema, failed(bridgeError("TOOL_NOT_FOUND", "The requested Omni tool is not available.")));
162
321
  }
163
- export function registerOmniTools(server, dependencies) {
164
- server.registerTool("parse_document", {
165
- description: `${SAFETY_INSTRUCTIONS}\n\nParse one local file through Omni without sending source bytes through the model or Cube-MCP.`,
166
- inputSchema: parseDocumentSchema,
322
+ export function registerOmniTools(server, dependencies, taskStore) {
323
+ const taskRuntime = new TaskRuntime({
324
+ parse: (source, signal) => parseValue({ source }, signal, NOOP_PROGRESS, dependencies),
325
+ status: (operationId, waitMs, signal) => statusValue(operationId, waitMs, signal, dependencies),
326
+ cancel: (operationId, signal) => cancelValue(operationId, signal, dependencies),
327
+ });
328
+ const createParseTask = async (args, extra) => {
329
+ const requestedTtl = extra.taskRequestedTtl ?? 600_000;
330
+ const task = await extra.taskStore.createTask({
331
+ ttl: Math.min(600_000, Math.max(1_000, requestedTtl)),
332
+ pollInterval: 1_000,
333
+ });
334
+ void taskRuntime.start(task.taskId, args.source, extra.taskStore)
335
+ .catch(() => undefined);
336
+ return { task };
337
+ };
338
+ const parseInputShape = parseSchema.shape;
339
+ const parseTaskHandler = {
340
+ createTask: createParseTask,
341
+ getTask: async (_args, extra) => extra.taskStore.getTask(extra.taskId),
342
+ getTaskResult: async (_args, extra) => await extra.taskStore.getTaskResult(extra.taskId),
343
+ };
344
+ server.experimental.tasks.registerToolTask("parse", {
345
+ description: `${MACHINE_INSTRUCTIONS}\n\nParse one local file or HTTP(S) URL through Omni.`,
346
+ inputSchema: parseInputShape,
347
+ outputSchema: parseToolOutputSchema,
348
+ execution: { taskSupport: "optional" },
167
349
  annotations: {
168
350
  readOnlyHint: false,
169
351
  destructiveHint: false,
170
352
  idempotentHint: false,
171
353
  openWorldHint: true,
172
354
  },
173
- }, async (args, extra) => {
174
- try {
175
- return await parseDocument(args, extra, dependencies);
176
- }
177
- catch (error) {
178
- return errorResult(error);
179
- }
180
- });
355
+ }, parseTaskHandler);
356
+ server.registerTool("get_parse_status", {
357
+ description: "Read the current state of one existing Omni parse operation.",
358
+ inputSchema: getParseStatusSchema,
359
+ outputSchema: parseToolOutputSchema,
360
+ annotations: {
361
+ readOnlyHint: true,
362
+ destructiveHint: false,
363
+ idempotentHint: true,
364
+ openWorldHint: true,
365
+ },
366
+ }, (args, extra) => callStatus(args.operation_id, args.wait_ms, extra, dependencies));
367
+ server.registerTool("cancel_parse", {
368
+ description: "Request cancellation of one existing Omni parse operation.",
369
+ inputSchema: cancelParseSchema,
370
+ outputSchema: parseToolOutputSchema,
371
+ annotations: {
372
+ readOnlyHint: false,
373
+ destructiveHint: true,
374
+ idempotentHint: true,
375
+ openWorldHint: true,
376
+ },
377
+ }, (args, extra) => callCancel(args.operation_id, extra, dependencies));
181
378
  server.registerTool("read_result", {
182
379
  description: "Read one UTF-8 chunk from a Bridge-created local result artifact.",
183
380
  inputSchema: readResultSchema,
381
+ outputSchema: readResultToolOutputSchema,
184
382
  annotations: {
185
383
  readOnlyHint: true,
186
384
  destructiveHint: false,
187
385
  idempotentHint: true,
188
386
  openWorldHint: false,
189
387
  },
190
- }, async (args) => {
191
- try {
192
- return readSuccess(await dependencies.artifactStore.read(args.result_id, args.cursor, args.max_bytes));
193
- }
194
- catch (error) {
195
- return errorResult(error);
196
- }
197
- });
388
+ }, (args) => callReadResult(args.result_id, args.cursor, args.max_bytes, dependencies));
198
389
  server.registerTool("discard_result", {
199
390
  description: "Immediately delete one Bridge-created local result artifact.",
200
391
  inputSchema: discardResultSchema,
392
+ outputSchema: discardResultToolOutputSchema,
201
393
  annotations: {
202
394
  readOnlyHint: false,
203
395
  destructiveHint: true,
204
396
  idempotentHint: true,
205
397
  openWorldHint: false,
206
398
  },
207
- }, async (args) => {
208
- try {
209
- return successResult({
210
- result_id: args.result_id,
211
- discarded: await dependencies.artifactStore.discard(args.result_id),
212
- });
213
- }
214
- catch (error) {
215
- return errorResult(error);
216
- }
217
- });
399
+ }, (args) => callDiscardResult(args.result_id, dependencies));
218
400
  server.server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
219
401
  if (request.params.task !== undefined) {
220
- return errorResult(bridgeError("TOOL_TASK_UNSUPPORTED", "Task-augmented tool calls are not supported by this Omni Bridge."));
402
+ if (request.params.name !== "parse") {
403
+ return structuredResult(parseResultSchema, failed(bridgeError("TOOL_TASK_UNSUPPORTED", "Task augmentation is supported only for Omni parse calls.")));
404
+ }
405
+ const parsed = parseSchema.safeParse(request.params.arguments ?? {});
406
+ if (!parsed.success || extra.taskStore === undefined) {
407
+ return invalidArgumentsResult(request.params.name);
408
+ }
409
+ return createParseTask(parsed.data, extra);
221
410
  }
222
411
  return dispatchTool(request.params.name, request.params.arguments, extra, dependencies);
223
412
  });
413
+ server.server.setRequestHandler(CancelTaskRequestSchema, async (request, extra) => {
414
+ const task = await taskStore.getTask(request.params.taskId, extra.sessionId);
415
+ if (task === null) {
416
+ throw new McpError(ErrorCode.InvalidParams, `Task not found: ${request.params.taskId}`);
417
+ }
418
+ if (["completed", "failed", "cancelled"].includes(task.status)) {
419
+ throw new McpError(ErrorCode.InvalidParams, `Cannot cancel task in terminal status: ${task.status}`);
420
+ }
421
+ await taskStore.updateTaskStatus(request.params.taskId, "cancelled", "Client cancelled task execution.", extra.sessionId);
422
+ await taskRuntime.cancel(request.params.taskId);
423
+ const canceled = await taskStore.getTask(request.params.taskId, extra.sessionId);
424
+ if (canceled === null) {
425
+ throw new McpError(ErrorCode.InvalidParams, `Task not found: ${request.params.taskId}`);
426
+ }
427
+ return { _meta: {}, ...canceled };
428
+ });
224
429
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cueai/omni-reader-mcp",
3
- "version": "1.0.2",
3
+ "version": "1.1.1",
4
4
  "description": "Local stdio MCP bridge for direct Omni document parsing",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",
@@ -19,12 +19,12 @@
19
19
  },
20
20
  "scripts": {
21
21
  "build": "tsc -p tsconfig.json",
22
- "test": "vitest run",
22
+ "test": "npm run build && vitest run",
23
23
  "typecheck": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.test.json --noEmit",
24
24
  "prepack": "npm run test && npm run build"
25
25
  },
26
26
  "dependencies": {
27
- "@modelcontextprotocol/sdk": "^1.24.0",
27
+ "@modelcontextprotocol/sdk": "1.30.0",
28
28
  "zod": "^3.25.0"
29
29
  },
30
30
  "devDependencies": {