document-mcp 4.6.24 → 4.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.
package/README.md CHANGED
@@ -209,27 +209,29 @@ Every tool that takes or produces document bytes goes through the same two hybri
209
209
 
210
210
  ## Tools
211
211
 
212
- | Tool | Description |
213
- | --------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
214
- | `convert_document` | Converts a document from one supported format to another via `documents.js`'s `DocumentConverter` port — docx, pptx, xlsx, odt, odp, ods, odg, odf, markdown, and pdf. Not every `(source, targetFormat)` pair is direct; call `list_document_conversions` first. |
215
- | `list_document_conversions` | Lists every `(source, target)` format pair `convert_document` actually supports. |
216
- | `metadata_read` | Reads a document's title/author/subject/keywords/creator/producer/created-and-modified timestamps. Works across every supported format, including xlsx and odf. |
217
- | `metadata_write` | Patches a document's title/author/subject/keywords in place. Does not convert format — source and target format must match (or both be `pdf`); odf (a standalone formula document) is rejected as either, since it has no write path back out at all. |
218
- | `fonts` | Lists every source-embedded font face a docx/pptx/odt/odp/ods/odg document carries (family, weight/style, byte length). |
219
- | `describe_font_file` | Reads a standalone `.ttf`/`.otf` font file and reports the family/bold/italic triple it declares about itself. |
220
- | `docx_extras` | Reads a docx's own comments, footnotes, header/footer parts, and numbering definitions — data the `ContentDocument` pivot cannot carry, so no other tool sees it. |
221
- | `pdf_inspect` | Parses a PDF and reports a summary (page count, per-page size and item-kind histogram, metadata, embedded image formats), or with `full: true` the entire parsed `LayoutDocument` as plain JSON — no `$schema` stamp, since that family moved to `pdf-codec` at `document-schema.js` 4.0.0 and lost its schema-stamped envelope. |
222
- | `odm_to_pdf` | Converts a `.odm` (ODF master document) to PDF. A `.odm` never carries its chapters' content inline, so each chapter resolves via a caller-supplied `chapters` href-to-document map and/or a `chaptersDir` searched by basename. |
223
- | `from_package` | Rebuilds real document bytes in a target format from a `DocumentTree` previously serialised to JSON (e.g. by a conversion tool's own `onDocument`/package-dump step). Only a package genuinely written by a current dump round-trips: the `$schema` URI it carries pins the `document-schema.js` release that wrote it, and a pre-4.0.0 dump (the flat `{ formatVersion, content, pages }` envelope) is rejected with an error naming the pinned release, the flat-to-tree change, and the remedy — a layout-document dump gets its own pointer, naming the move to `pdf-codec`. |
224
- | `outline_document` | Projects a document's own table of contents as structured JSON: groups (`{ text, level, children }`) for headings, list items, slides, sheets, and draw pages, leaves (`{ kind, text }`) for the content between them. The outline is over the source's own native content read directly via `documents.js`'s `readNativeDocumentTree` (no bridging conversion, no discarded output bytes) and built by `document-outline.js`'s `buildOutline`. |
225
- | `compute_formula` | Reads every formula a document embeds (docx/odt/markdown paragraphs and pptx/odp slide shapes; a table cell's own blocks too — docx's own reader recovers a real equation nested inside a table cell; structurally, the walk also covers a drawing page's own shape flow, though no writer in the family populates a formula there today; a spreadsheet's own cell-anchored formula objects; a standalone `.odf` formula document; and a formula nested inside another embedded object at any depth — e.g. a formula embedded in a drawing embedded in a spreadsheet) and evaluates each through `document-compute.js`'s units-typed `evaluate()` an agent's way to check whether a document's stated arithmetic actually checks out. A formula referencing a symbol needs that symbol's value supplied via `bindings`, keyed by the document's own symbol-table id; each formula reports its own outcome independently (`evaluated`, `no-content`, or `error`), so one formula needing more bindings never blocks the others. |
226
- | `odb_tables` | Lists every table an embedded `.odb` database declares column names, types, and row dataacross every storage tier `documents.js` supports (HSQLDB TEXT/CACHED/BINARY, Firebird gbak backups). |
227
- | `odb_forms` | Lists every form an `.odb` database declares, with each form's own data source and field-bound controls. |
228
- | `odb_reports` | Lists every report an `.odb` database declares, with each report's own data-source command, band/group structure, and `rpt:` formula expressions. |
229
- | `odb_query` | Runs a bounded `SELECT` (with optional INNER JOINs) over an embedded `.odb` database's extracted tables — given directly as SQL or by naming a saved query. No database engine involved; no OUTER/LEFT/RIGHT/FULL/CROSS/NATURAL joins, subqueries, or table aliases; an unsupported construct is reported as a tool error naming it, never silently ignored. |
230
- | `odb_to_csv` | Extracts exactly one named table from an embedded `.odb` database as CSV bytes. The table name is required whenever the database declares more than one table. |
231
- | `odb_to_xlsx` | Extracts every table an embedded `.odb` database declares into one xlsx workbook, one sheet per table. |
232
- | `odb_render_report` | Resolves one of an `.odb` database's own reports its data-bound command run through the bounded SQL engine, its `rpt:` formulas evaluated, its bands laid out — and renders the result to docx, odt, or pdf. |
212
+ | Tool | Description |
213
+ | ---------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
214
+ | `convert_document` | Converts a document from one supported format to another via `documents.js`'s `DocumentConverter` port — docx, pptx, xlsx, odt, odp, ods, odg, odf, markdown, and pdf. Not every `(source, targetFormat)` pair is direct; call `list_document_conversions` first. |
215
+ | `list_document_conversions` | Lists every `(source, target)` format pair `convert_document` actually supports. |
216
+ | `metadata_read` | Reads a document's title/author/subject/keywords/creator/producer/created-and-modified timestamps. Works across every supported format, including xlsx and odf. |
217
+ | `metadata_write` | Patches a document's title/author/subject/keywords in place. Does not convert format — source and target format must match (or both be `pdf`); odf (a standalone formula document) is rejected as either, since it has no write path back out at all. |
218
+ | `document_create` | Creates a fresh, blank document via `documents.js`'s own live-view editors (`createDocx`/`createOdt`/`createMarkdownEditor`/...) docx, pptx, odt, odp, ods, odg, pdf, or markdown. |
219
+ | `document_append_paragraphs` | Appends one or more paragraphs — each optionally built from several independently-formatted runs — to the end of a docx, odt, or markdown document, through the same live-view editors `document_create` and document-cli's own TUI use. Does not convert format — source and targetFormat must match. docx and odt share an identical field set (underline, fontFamily, sizePt, colour, headingLevel, alignment); markdown supports a smaller, different set (hyperlink, inline code) and rejects a docx/odt-only field outright rather than silently dropping it. Covers wordprocessing paragraph/run editing only — slides, sheets, drawings, tables, lists, and images are a separate editing surface not exposed here yet. |
220
+ | `fonts` | Lists every source-embedded font face a docx/pptx/odt/odp/ods/odg document carries (family, weight/style, byte length). |
221
+ | `describe_font_file` | Reads a standalone `.ttf`/`.otf` font file and reports the family/bold/italic triple it declares about itself. |
222
+ | `docx_extras` | Reads a docx's own comments, footnotes, header/footer parts, and numbering definitions data the `ContentDocument` pivot cannot carry, so no other tool sees it. |
223
+ | `pdf_inspect` | Parses a PDF and reports a summary (page count, per-page size and item-kind histogram, metadata, embedded image formats), or with `full: true` the entire parsed `LayoutDocument` as plain JSON no `$schema` stamp, since that family moved to `pdf-codec` at `document-schema.js` 4.0.0 and lost its schema-stamped envelope. |
224
+ | `odm_to_pdf` | Converts a `.odm` (ODF master document) to PDF. A `.odm` never carries its chapters' content inline, so each chapter resolves via a caller-supplied `chapters` href-to-document map and/or a `chaptersDir` searched by basename. |
225
+ | `from_package` | Rebuilds real document bytes in a target format from a `DocumentTree` previously serialised to JSON (e.g. by a conversion tool's own `onDocument`/package-dump step). Only a package genuinely written by a current dump round-trips: the `$schema` URI it carries pins the `document-schema.js` release that wrote it, and a pre-4.0.0 dump (the flat `{ formatVersion, content, pages }` envelope) is rejected with an error naming the pinned release, the flat-to-tree change, and the remedy a layout-document dump gets its own pointer, naming the move to `pdf-codec`. |
226
+ | `outline_document` | Projects a document's own table of contents as structured JSON: groups (`{ text, level, children }`) for headings, list items, slides, sheets, and draw pages, leaves (`{ kind, text }`) for the content between them. The outline is over the source's own native content read directly via `documents.js`'s `readNativeDocumentTree` (no bridging conversion, no discarded output bytes) and built by `document-outline.js`'s `buildOutline`. |
227
+ | `compute_formula` | Reads every formula a document embeds (docx/odt/markdown paragraphs and pptx/odp slide shapes; a table cell's own blocks too — docx's own reader recovers a real equation nested inside a table cell; structurally, the walk also covers a drawing page's own shape flow, though no writer in the family populates a formula there today; a spreadsheet's own cell-anchored formula objects; a standalone `.odf` formula document; and a formula nested inside another embedded object at any depth — e.g. a formula embedded in a drawing embedded in a spreadsheet) and evaluates each through `document-compute.js`'s units-typed `evaluate()` — an agent's way to check whether a document's stated arithmetic actually checks out. A formula referencing a symbol needs that symbol's value supplied via `bindings`, keyed by the document's own symbol-table id; each formula reports its own outcome independently (`evaluated`, `no-content`, or `error`), so one formula needing more bindings never blocks the others. |
228
+ | `odb_tables` | Lists every table an embedded `.odb` database declares — column names, types, and row data across every storage tier `documents.js` supports (HSQLDB TEXT/CACHED/BINARY, Firebird gbak backups). |
229
+ | `odb_forms` | Lists every form an `.odb` database declares, with each form's own data source and field-bound controls. |
230
+ | `odb_reports` | Lists every report an `.odb` database declares, with each report's own data-source command, band/group structure, and `rpt:` formula expressions. |
231
+ | `odb_query` | Runs a bounded `SELECT` (with optional INNER JOINs) over an embedded `.odb` database's extracted tables given directly as SQL or by naming a saved query. No database engine involved; no OUTER/LEFT/RIGHT/FULL/CROSS/NATURAL joins, subqueries, or table aliases; an unsupported construct is reported as a tool error naming it, never silently ignored. |
232
+ | `odb_to_csv` | Extracts exactly one named table from an embedded `.odb` database as CSV bytes. The table name is required whenever the database declares more than one table. |
233
+ | `odb_to_xlsx` | Extracts every table an embedded `.odb` database declares into one xlsx workbook, one sheet per table. |
234
+ | `odb_render_report` | Resolves one of an `.odb` database's own reports — its data-bound command run through the bounded SQL engine, its `rpt:` formulas evaluated, its bands laid out — and renders the result to docx, odt, or pdf. |
233
235
 
234
236
  ## References
235
237
 
package/dist/bin.js CHANGED
@@ -5,14 +5,14 @@ import { toNodeHandler } from "@modelcontextprotocol/node";
5
5
  import { McpServer, createMcpHandler } from "@modelcontextprotocol/server";
6
6
  import { evaluate } from "document-compute.js";
7
7
  import { ContentDocumentSchema, EvaluationValueSchema, FormulaBindingsSchema, flattenTree } from "document-schema.js";
8
- import { DocumentFormatSchema, OdbReportNotSpecifiedError, OdmUnresolvedSectionError, UnrecognizedDocumentSchemaError, base64ToBytes, buildDocumentBytes, bytesToBase64, collectDocumentFormulas, createLocalDocumentConverter, decodeOdbPackage, decodePackage, describeFontFace, documentFromJson, documentSchemaKindOf, evaluateSelect, extractSourceFontsForFormat, odbReportToDocx, odbReportToOdt, odbReportToPdf, odbToCsv, odbToXlsx, odmToPdf, parseSelect, readDocumentMetadata, readDocxExtras, readNativeDocumentTree, readOdbForms, readOdbInventory, readOdbReportContent, readOdbReports, readOdbTables, readPdf, setDocumentMetadata } from "documents.js";
8
+ import { DocumentFormatSchema, OdbReportNotSpecifiedError, OdmUnresolvedSectionError, UnrecognizedDocumentSchemaError, base64ToBytes, buildDocumentBytes, bytesToBase64, collectDocumentFormulas, createDocx, createLocalDocumentConverter, createMarkdownEditor, createOdg, createOdp, createOds, createOdt, createPdf, createPptx, decodeMarkdownText, decodeOdbPackage, decodePackage, describeFontFace, documentFromJson, documentSchemaKindOf, encodeMarkdownText, evaluateSelect, extractSourceFontsForFormat, odbReportToDocx, odbReportToOdt, odbReportToPdf, odbToCsv, odbToXlsx, odmToPdf, openDocx, openMarkdown, openOdt, parseSelect, readDocumentMetadata, readDocxExtras, readNativeDocumentTree, readOdbForms, readOdbInventory, readOdbReportContent, readOdbReports, readOdbTables, readPdf, rgbHexToColor, setDocumentMetadata } from "documents.js";
9
9
  import { z } from "zod";
10
10
  import { readFile, writeFile } from "node:fs/promises";
11
11
  import { existsSync, readFileSync } from "node:fs";
12
12
  import { basename, join } from "node:path";
13
13
  import { buildOutline, isOutlineNode, outlineLeafText } from "document-outline.js";
14
14
  //#region package.json
15
- var version = "4.6.24";
15
+ var version = "4.7.0";
16
16
  //#endregion
17
17
  //#region src/io/document-input.ts
18
18
  const EXTENSION_TO_FORMAT = {
@@ -77,7 +77,7 @@ async function resolveDocumentInput(input, options) {
77
77
  }
78
78
  //#endregion
79
79
  //#region src/tools/compute-formula.ts
80
- function toErrorResult$2(error) {
80
+ function toErrorResult$3(error) {
81
81
  return {
82
82
  content: [{
83
83
  type: "text",
@@ -164,7 +164,7 @@ function registerComputeFormulaTools(server) {
164
164
  structuredContent
165
165
  };
166
166
  } catch (error) {
167
- return toErrorResult$2(error);
167
+ return toErrorResult$3(error);
168
168
  }
169
169
  });
170
170
  }
@@ -328,6 +328,184 @@ function registerDocxExtrasTools(server) {
328
328
  });
329
329
  }
330
330
  //#endregion
331
+ //#region src/tools/editor.ts
332
+ function toErrorResult$2(error) {
333
+ return {
334
+ content: [{
335
+ type: "text",
336
+ text: error instanceof Error ? error.message : String(error)
337
+ }],
338
+ isError: true
339
+ };
340
+ }
341
+ const WritableFormatSchema = z.enum([
342
+ "docx",
343
+ "pptx",
344
+ "odt",
345
+ "odp",
346
+ "ods",
347
+ "odg",
348
+ "pdf",
349
+ "markdown"
350
+ ]);
351
+ const RunSchema = z.object({
352
+ text: z.string().optional().describe("The run's own text content."),
353
+ bold: z.boolean().optional(),
354
+ italic: z.boolean().optional(),
355
+ strike: z.boolean().optional(),
356
+ underline: z.boolean().optional().describe("docx/odt only."),
357
+ fontFamily: z.string().optional().describe("docx/odt only."),
358
+ sizePt: z.number().positive().optional().describe("docx/odt only."),
359
+ colorHex: z.string().regex(/^#?[0-9a-fA-F]{6}$/).optional().describe("6-digit hex colour (e.g. 'ff0000' or '#ff0000'). docx/odt only."),
360
+ hyperlink: z.string().optional().describe("markdown only."),
361
+ code: z.boolean().optional().describe("markdown only -- renders the run as an inline code span.")
362
+ });
363
+ const ParagraphSchema = z.object({
364
+ text: z.string().optional().describe("Plain paragraph text, as a single run. Omit and use `runs` instead for mixed formatting within one paragraph."),
365
+ styleId: z.string().optional(),
366
+ headingLevel: z.number().int().min(1).max(6).optional().describe("docx/odt only."),
367
+ alignment: z.enum([
368
+ "left",
369
+ "center",
370
+ "right",
371
+ "justify"
372
+ ]).optional().describe("docx/odt only."),
373
+ runs: z.array(RunSchema).optional().describe("Runs to append to this paragraph, each with its own formatting. Combine with `text` for a paragraph that opens with plain text before its first formatted run, or omit `text` entirely for a paragraph built purely from runs.")
374
+ });
375
+ function unsupportedFieldNames(input, unsupported) {
376
+ return unsupported.filter((key) => input[key] !== void 0);
377
+ }
378
+ function rejectUnsupportedFields(input, unsupported, formatLabel, context) {
379
+ const present = unsupportedFieldNames(input, unsupported);
380
+ if (present.length > 0) throw new Error(`${context} does not support ${present.join(", ")} for ${formatLabel} -- remove ${present.length === 1 ? "it" : "them"} or target docx/odt instead.`);
381
+ }
382
+ const DOCX_ODT_UNSUPPORTED_RUN_FIELDS = ["hyperlink", "code"];
383
+ const MARKDOWN_UNSUPPORTED_RUN_FIELDS = [
384
+ "underline",
385
+ "fontFamily",
386
+ "sizePt",
387
+ "colorHex"
388
+ ];
389
+ const MARKDOWN_UNSUPPORTED_PARAGRAPH_FIELDS = ["headingLevel", "alignment"];
390
+ function appendDocxOdtRun(paragraph, run) {
391
+ rejectUnsupportedFields(run, DOCX_ODT_UNSUPPORTED_RUN_FIELDS, "docx/odt", "A run");
392
+ paragraph.appendRun({
393
+ text: run.text,
394
+ bold: run.bold,
395
+ italic: run.italic,
396
+ underline: run.underline,
397
+ strike: run.strike,
398
+ fontFamily: run.fontFamily,
399
+ sizePt: run.sizePt,
400
+ color: run.colorHex === void 0 ? void 0 : rgbHexToColor(run.colorHex)
401
+ });
402
+ }
403
+ function appendDocxOdtParagraphs(body, paragraphs) {
404
+ for (const paragraph of paragraphs) {
405
+ const built = body.appendParagraph({
406
+ text: paragraph.text,
407
+ styleId: paragraph.styleId,
408
+ headingLevel: paragraph.headingLevel,
409
+ alignment: paragraph.alignment
410
+ });
411
+ for (const run of paragraph.runs ?? []) appendDocxOdtRun(built, run);
412
+ }
413
+ }
414
+ function appendMarkdownParagraphs(body, paragraphs) {
415
+ for (const paragraph of paragraphs) {
416
+ rejectUnsupportedFields(paragraph, MARKDOWN_UNSUPPORTED_PARAGRAPH_FIELDS, "markdown", "A paragraph");
417
+ const built = body.appendParagraph({
418
+ text: paragraph.text,
419
+ styleId: paragraph.styleId
420
+ });
421
+ for (const run of paragraph.runs ?? []) {
422
+ rejectUnsupportedFields(run, MARKDOWN_UNSUPPORTED_RUN_FIELDS, "markdown", "A run");
423
+ built.appendRun({
424
+ text: run.text,
425
+ bold: run.bold,
426
+ italic: run.italic,
427
+ strike: run.strike,
428
+ hyperlink: run.hyperlink,
429
+ code: run.code
430
+ });
431
+ }
432
+ }
433
+ }
434
+ function createDocumentBytes(format) {
435
+ switch (format) {
436
+ case "docx": return createDocx().toBytes();
437
+ case "pptx": return createPptx().toBytes();
438
+ case "odt": return createOdt().toBytes();
439
+ case "odp": return createOdp().toBytes();
440
+ case "ods": return createOds().toBytes();
441
+ case "odg": return createOdg().toBytes();
442
+ case "pdf": return createPdf().toBytes();
443
+ case "markdown": return encodeMarkdownText(createMarkdownEditor().toMarkdownText());
444
+ }
445
+ }
446
+ function registerEditorTools(server) {
447
+ server.registerTool("document_create", {
448
+ title: "Create a blank document",
449
+ description: "Creates a fresh, blank document in the given format via documents.js's own live-view editors (createDocx/createOdt/createMarkdownEditor/...), the same construction document_append_paragraphs's own edit calls build on. Returns an empty document with no content -- follow with document_append_paragraphs (docx/odt/markdown) to add text.",
450
+ inputSchema: z.object({
451
+ format: WritableFormatSchema.describe("The format of document to create."),
452
+ output: DocumentOutputSchema.optional().describe("Where to write the created document. Omit entirely to receive the bytes inline, base64-encoded.")
453
+ })
454
+ }, async ({ format, output }) => {
455
+ try {
456
+ const resolvedOutput = await resolveDocumentOutput(createDocumentBytes(format), output ?? {});
457
+ return {
458
+ content: [{
459
+ type: "text",
460
+ text: JSON.stringify(resolvedOutput)
461
+ }],
462
+ structuredContent: resolvedOutput
463
+ };
464
+ } catch (error) {
465
+ return toErrorResult$2(error);
466
+ }
467
+ });
468
+ server.registerTool("document_append_paragraphs", {
469
+ title: "Append paragraphs to a wordprocessing document",
470
+ description: "Appends one or more paragraphs -- each optionally built from several independently-formatted runs -- to the end of a docx, odt, or markdown document, through documents.js's own live-view editors (the same DocxBody.appendParagraph/OdtBody.appendParagraph/MarkdownBody.appendParagraph document-cli's own TUI uses). Does not convert format -- the source document's own format and targetFormat must match. docx and odt share an identical field set (underline, fontFamily, sizePt, colorHex, headingLevel, alignment all supported); markdown supports a different, smaller set (hyperlink, code) and rejects the docx/odt-only fields outright rather than silently dropping them. This covers wordprocessing paragraph/run editing only -- slides, sheets, drawings, tables, lists, and images are a separate, larger editing surface not exposed here yet.",
471
+ inputSchema: z.object({
472
+ source: DocumentInputSchema.describe("The document to append paragraphs to."),
473
+ targetFormat: z.enum([
474
+ "docx",
475
+ "odt",
476
+ "markdown"
477
+ ]).describe("Must match the source document's own format. document_append_paragraphs never converts format."),
478
+ paragraphs: z.array(ParagraphSchema).min(1).describe("The paragraphs to append, in order."),
479
+ output: DocumentOutputSchema.optional().describe("Where to write the edited document. Omit entirely to receive the bytes inline, base64-encoded.")
480
+ })
481
+ }, async ({ source, targetFormat, paragraphs, output }) => {
482
+ try {
483
+ const { bytes, format } = await resolveDocumentInput(source);
484
+ if (format !== targetFormat) throw new Error(`source document is "${format}", but targetFormat is "${targetFormat}" -- document_append_paragraphs never converts format, so the two must match.`);
485
+ let resultBytes;
486
+ if (targetFormat === "markdown") {
487
+ const editor = openMarkdown(decodeMarkdownText(bytes));
488
+ appendMarkdownParagraphs(editor.body, paragraphs);
489
+ resultBytes = encodeMarkdownText(editor.toMarkdownText());
490
+ } else {
491
+ const editor = targetFormat === "docx" ? openDocx(bytes) : openOdt(bytes);
492
+ appendDocxOdtParagraphs(editor.body, paragraphs);
493
+ resultBytes = editor.toBytes();
494
+ }
495
+ const resolvedOutput = await resolveDocumentOutput(resultBytes, output ?? {});
496
+ return {
497
+ content: [{
498
+ type: "text",
499
+ text: JSON.stringify(resolvedOutput)
500
+ }],
501
+ structuredContent: resolvedOutput
502
+ };
503
+ } catch (error) {
504
+ return toErrorResult$2(error);
505
+ }
506
+ });
507
+ }
508
+ //#endregion
331
509
  //#region src/tools/fonts.ts
332
510
  const FontFileInputSchema = z.union([z.object({ path: z.string().describe("Filesystem path to the font file (.ttf/.otf) to read.") }), z.object({ bytesBase64: z.string().describe("Base64-encoded font file bytes.") })]);
333
511
  async function resolveFontFileInput(input) {
@@ -976,6 +1154,7 @@ function createServer$1() {
976
1154
  registerComputeFormulaTools(server);
977
1155
  registerConvertTools(server);
978
1156
  registerDocxExtrasTools(server);
1157
+ registerEditorTools(server);
979
1158
  registerFontTools(server);
980
1159
  registerFromPackageTools(server);
981
1160
  registerMetadataTools(server);
package/dist/index.cjs CHANGED
@@ -9,7 +9,7 @@ let node_fs = require("node:fs");
9
9
  let node_path = require("node:path");
10
10
  let document_outline_js = require("document-outline.js");
11
11
  //#region package.json
12
- var version = "4.6.24";
12
+ var version = "4.7.0";
13
13
  //#endregion
14
14
  //#region src/io/document-input.ts
15
15
  const EXTENSION_TO_FORMAT = {
@@ -74,7 +74,7 @@ async function resolveDocumentInput(input, options) {
74
74
  }
75
75
  //#endregion
76
76
  //#region src/tools/compute-formula.ts
77
- function toErrorResult$2(error) {
77
+ function toErrorResult$3(error) {
78
78
  return {
79
79
  content: [{
80
80
  type: "text",
@@ -161,7 +161,7 @@ function registerComputeFormulaTools(server) {
161
161
  structuredContent
162
162
  };
163
163
  } catch (error) {
164
- return toErrorResult$2(error);
164
+ return toErrorResult$3(error);
165
165
  }
166
166
  });
167
167
  }
@@ -325,6 +325,184 @@ function registerDocxExtrasTools(server) {
325
325
  });
326
326
  }
327
327
  //#endregion
328
+ //#region src/tools/editor.ts
329
+ function toErrorResult$2(error) {
330
+ return {
331
+ content: [{
332
+ type: "text",
333
+ text: error instanceof Error ? error.message : String(error)
334
+ }],
335
+ isError: true
336
+ };
337
+ }
338
+ const WritableFormatSchema = zod.z.enum([
339
+ "docx",
340
+ "pptx",
341
+ "odt",
342
+ "odp",
343
+ "ods",
344
+ "odg",
345
+ "pdf",
346
+ "markdown"
347
+ ]);
348
+ const RunSchema = zod.z.object({
349
+ text: zod.z.string().optional().describe("The run's own text content."),
350
+ bold: zod.z.boolean().optional(),
351
+ italic: zod.z.boolean().optional(),
352
+ strike: zod.z.boolean().optional(),
353
+ underline: zod.z.boolean().optional().describe("docx/odt only."),
354
+ fontFamily: zod.z.string().optional().describe("docx/odt only."),
355
+ sizePt: zod.z.number().positive().optional().describe("docx/odt only."),
356
+ colorHex: zod.z.string().regex(/^#?[0-9a-fA-F]{6}$/).optional().describe("6-digit hex colour (e.g. 'ff0000' or '#ff0000'). docx/odt only."),
357
+ hyperlink: zod.z.string().optional().describe("markdown only."),
358
+ code: zod.z.boolean().optional().describe("markdown only -- renders the run as an inline code span.")
359
+ });
360
+ const ParagraphSchema = zod.z.object({
361
+ text: zod.z.string().optional().describe("Plain paragraph text, as a single run. Omit and use `runs` instead for mixed formatting within one paragraph."),
362
+ styleId: zod.z.string().optional(),
363
+ headingLevel: zod.z.number().int().min(1).max(6).optional().describe("docx/odt only."),
364
+ alignment: zod.z.enum([
365
+ "left",
366
+ "center",
367
+ "right",
368
+ "justify"
369
+ ]).optional().describe("docx/odt only."),
370
+ runs: zod.z.array(RunSchema).optional().describe("Runs to append to this paragraph, each with its own formatting. Combine with `text` for a paragraph that opens with plain text before its first formatted run, or omit `text` entirely for a paragraph built purely from runs.")
371
+ });
372
+ function unsupportedFieldNames(input, unsupported) {
373
+ return unsupported.filter((key) => input[key] !== void 0);
374
+ }
375
+ function rejectUnsupportedFields(input, unsupported, formatLabel, context) {
376
+ const present = unsupportedFieldNames(input, unsupported);
377
+ if (present.length > 0) throw new Error(`${context} does not support ${present.join(", ")} for ${formatLabel} -- remove ${present.length === 1 ? "it" : "them"} or target docx/odt instead.`);
378
+ }
379
+ const DOCX_ODT_UNSUPPORTED_RUN_FIELDS = ["hyperlink", "code"];
380
+ const MARKDOWN_UNSUPPORTED_RUN_FIELDS = [
381
+ "underline",
382
+ "fontFamily",
383
+ "sizePt",
384
+ "colorHex"
385
+ ];
386
+ const MARKDOWN_UNSUPPORTED_PARAGRAPH_FIELDS = ["headingLevel", "alignment"];
387
+ function appendDocxOdtRun(paragraph, run) {
388
+ rejectUnsupportedFields(run, DOCX_ODT_UNSUPPORTED_RUN_FIELDS, "docx/odt", "A run");
389
+ paragraph.appendRun({
390
+ text: run.text,
391
+ bold: run.bold,
392
+ italic: run.italic,
393
+ underline: run.underline,
394
+ strike: run.strike,
395
+ fontFamily: run.fontFamily,
396
+ sizePt: run.sizePt,
397
+ color: run.colorHex === void 0 ? void 0 : (0, documents_js.rgbHexToColor)(run.colorHex)
398
+ });
399
+ }
400
+ function appendDocxOdtParagraphs(body, paragraphs) {
401
+ for (const paragraph of paragraphs) {
402
+ const built = body.appendParagraph({
403
+ text: paragraph.text,
404
+ styleId: paragraph.styleId,
405
+ headingLevel: paragraph.headingLevel,
406
+ alignment: paragraph.alignment
407
+ });
408
+ for (const run of paragraph.runs ?? []) appendDocxOdtRun(built, run);
409
+ }
410
+ }
411
+ function appendMarkdownParagraphs(body, paragraphs) {
412
+ for (const paragraph of paragraphs) {
413
+ rejectUnsupportedFields(paragraph, MARKDOWN_UNSUPPORTED_PARAGRAPH_FIELDS, "markdown", "A paragraph");
414
+ const built = body.appendParagraph({
415
+ text: paragraph.text,
416
+ styleId: paragraph.styleId
417
+ });
418
+ for (const run of paragraph.runs ?? []) {
419
+ rejectUnsupportedFields(run, MARKDOWN_UNSUPPORTED_RUN_FIELDS, "markdown", "A run");
420
+ built.appendRun({
421
+ text: run.text,
422
+ bold: run.bold,
423
+ italic: run.italic,
424
+ strike: run.strike,
425
+ hyperlink: run.hyperlink,
426
+ code: run.code
427
+ });
428
+ }
429
+ }
430
+ }
431
+ function createDocumentBytes(format) {
432
+ switch (format) {
433
+ case "docx": return (0, documents_js.createDocx)().toBytes();
434
+ case "pptx": return (0, documents_js.createPptx)().toBytes();
435
+ case "odt": return (0, documents_js.createOdt)().toBytes();
436
+ case "odp": return (0, documents_js.createOdp)().toBytes();
437
+ case "ods": return (0, documents_js.createOds)().toBytes();
438
+ case "odg": return (0, documents_js.createOdg)().toBytes();
439
+ case "pdf": return (0, documents_js.createPdf)().toBytes();
440
+ case "markdown": return (0, documents_js.encodeMarkdownText)((0, documents_js.createMarkdownEditor)().toMarkdownText());
441
+ }
442
+ }
443
+ function registerEditorTools(server) {
444
+ server.registerTool("document_create", {
445
+ title: "Create a blank document",
446
+ description: "Creates a fresh, blank document in the given format via documents.js's own live-view editors (createDocx/createOdt/createMarkdownEditor/...), the same construction document_append_paragraphs's own edit calls build on. Returns an empty document with no content -- follow with document_append_paragraphs (docx/odt/markdown) to add text.",
447
+ inputSchema: zod.z.object({
448
+ format: WritableFormatSchema.describe("The format of document to create."),
449
+ output: DocumentOutputSchema.optional().describe("Where to write the created document. Omit entirely to receive the bytes inline, base64-encoded.")
450
+ })
451
+ }, async ({ format, output }) => {
452
+ try {
453
+ const resolvedOutput = await resolveDocumentOutput(createDocumentBytes(format), output ?? {});
454
+ return {
455
+ content: [{
456
+ type: "text",
457
+ text: JSON.stringify(resolvedOutput)
458
+ }],
459
+ structuredContent: resolvedOutput
460
+ };
461
+ } catch (error) {
462
+ return toErrorResult$2(error);
463
+ }
464
+ });
465
+ server.registerTool("document_append_paragraphs", {
466
+ title: "Append paragraphs to a wordprocessing document",
467
+ description: "Appends one or more paragraphs -- each optionally built from several independently-formatted runs -- to the end of a docx, odt, or markdown document, through documents.js's own live-view editors (the same DocxBody.appendParagraph/OdtBody.appendParagraph/MarkdownBody.appendParagraph document-cli's own TUI uses). Does not convert format -- the source document's own format and targetFormat must match. docx and odt share an identical field set (underline, fontFamily, sizePt, colorHex, headingLevel, alignment all supported); markdown supports a different, smaller set (hyperlink, code) and rejects the docx/odt-only fields outright rather than silently dropping them. This covers wordprocessing paragraph/run editing only -- slides, sheets, drawings, tables, lists, and images are a separate, larger editing surface not exposed here yet.",
468
+ inputSchema: zod.z.object({
469
+ source: DocumentInputSchema.describe("The document to append paragraphs to."),
470
+ targetFormat: zod.z.enum([
471
+ "docx",
472
+ "odt",
473
+ "markdown"
474
+ ]).describe("Must match the source document's own format. document_append_paragraphs never converts format."),
475
+ paragraphs: zod.z.array(ParagraphSchema).min(1).describe("The paragraphs to append, in order."),
476
+ output: DocumentOutputSchema.optional().describe("Where to write the edited document. Omit entirely to receive the bytes inline, base64-encoded.")
477
+ })
478
+ }, async ({ source, targetFormat, paragraphs, output }) => {
479
+ try {
480
+ const { bytes, format } = await resolveDocumentInput(source);
481
+ if (format !== targetFormat) throw new Error(`source document is "${format}", but targetFormat is "${targetFormat}" -- document_append_paragraphs never converts format, so the two must match.`);
482
+ let resultBytes;
483
+ if (targetFormat === "markdown") {
484
+ const editor = (0, documents_js.openMarkdown)((0, documents_js.decodeMarkdownText)(bytes));
485
+ appendMarkdownParagraphs(editor.body, paragraphs);
486
+ resultBytes = (0, documents_js.encodeMarkdownText)(editor.toMarkdownText());
487
+ } else {
488
+ const editor = targetFormat === "docx" ? (0, documents_js.openDocx)(bytes) : (0, documents_js.openOdt)(bytes);
489
+ appendDocxOdtParagraphs(editor.body, paragraphs);
490
+ resultBytes = editor.toBytes();
491
+ }
492
+ const resolvedOutput = await resolveDocumentOutput(resultBytes, output ?? {});
493
+ return {
494
+ content: [{
495
+ type: "text",
496
+ text: JSON.stringify(resolvedOutput)
497
+ }],
498
+ structuredContent: resolvedOutput
499
+ };
500
+ } catch (error) {
501
+ return toErrorResult$2(error);
502
+ }
503
+ });
504
+ }
505
+ //#endregion
328
506
  //#region src/tools/fonts.ts
329
507
  const FontFileInputSchema = zod.z.union([zod.z.object({ path: zod.z.string().describe("Filesystem path to the font file (.ttf/.otf) to read.") }), zod.z.object({ bytesBase64: zod.z.string().describe("Base64-encoded font file bytes.") })]);
330
508
  async function resolveFontFileInput(input) {
@@ -973,6 +1151,7 @@ function createServer() {
973
1151
  registerComputeFormulaTools(server);
974
1152
  registerConvertTools(server);
975
1153
  registerDocxExtrasTools(server);
1154
+ registerEditorTools(server);
976
1155
  registerFontTools(server);
977
1156
  registerFromPackageTools(server);
978
1157
  registerMetadataTools(server);
package/dist/index.js CHANGED
@@ -1,14 +1,14 @@
1
1
  import { McpServer } from "@modelcontextprotocol/server";
2
2
  import { evaluate } from "document-compute.js";
3
3
  import { ContentDocumentSchema, EvaluationValueSchema, FormulaBindingsSchema, flattenTree } from "document-schema.js";
4
- import { DocumentFormatSchema, OdbReportNotSpecifiedError, OdmUnresolvedSectionError, UnrecognizedDocumentSchemaError, base64ToBytes, buildDocumentBytes, bytesToBase64, collectDocumentFormulas, createLocalDocumentConverter, decodeOdbPackage, decodePackage, describeFontFace, documentFromJson, documentSchemaKindOf, evaluateSelect, extractSourceFontsForFormat, odbReportToDocx, odbReportToOdt, odbReportToPdf, odbToCsv, odbToXlsx, odmToPdf, parseSelect, readDocumentMetadata, readDocxExtras, readNativeDocumentTree, readOdbForms, readOdbInventory, readOdbReportContent, readOdbReports, readOdbTables, readPdf, setDocumentMetadata } from "documents.js";
4
+ import { DocumentFormatSchema, OdbReportNotSpecifiedError, OdmUnresolvedSectionError, UnrecognizedDocumentSchemaError, base64ToBytes, buildDocumentBytes, bytesToBase64, collectDocumentFormulas, createDocx, createLocalDocumentConverter, createMarkdownEditor, createOdg, createOdp, createOds, createOdt, createPdf, createPptx, decodeMarkdownText, decodeOdbPackage, decodePackage, describeFontFace, documentFromJson, documentSchemaKindOf, encodeMarkdownText, evaluateSelect, extractSourceFontsForFormat, odbReportToDocx, odbReportToOdt, odbReportToPdf, odbToCsv, odbToXlsx, odmToPdf, openDocx, openMarkdown, openOdt, parseSelect, readDocumentMetadata, readDocxExtras, readNativeDocumentTree, readOdbForms, readOdbInventory, readOdbReportContent, readOdbReports, readOdbTables, readPdf, rgbHexToColor, setDocumentMetadata } from "documents.js";
5
5
  import { z } from "zod";
6
6
  import { readFile, writeFile } from "node:fs/promises";
7
7
  import { existsSync, readFileSync } from "node:fs";
8
8
  import { basename, join } from "node:path";
9
9
  import { buildOutline, isOutlineNode, outlineLeafText } from "document-outline.js";
10
10
  //#region package.json
11
- var version = "4.6.24";
11
+ var version = "4.7.0";
12
12
  //#endregion
13
13
  //#region src/io/document-input.ts
14
14
  const EXTENSION_TO_FORMAT = {
@@ -73,7 +73,7 @@ async function resolveDocumentInput(input, options) {
73
73
  }
74
74
  //#endregion
75
75
  //#region src/tools/compute-formula.ts
76
- function toErrorResult$2(error) {
76
+ function toErrorResult$3(error) {
77
77
  return {
78
78
  content: [{
79
79
  type: "text",
@@ -160,7 +160,7 @@ function registerComputeFormulaTools(server) {
160
160
  structuredContent
161
161
  };
162
162
  } catch (error) {
163
- return toErrorResult$2(error);
163
+ return toErrorResult$3(error);
164
164
  }
165
165
  });
166
166
  }
@@ -324,6 +324,184 @@ function registerDocxExtrasTools(server) {
324
324
  });
325
325
  }
326
326
  //#endregion
327
+ //#region src/tools/editor.ts
328
+ function toErrorResult$2(error) {
329
+ return {
330
+ content: [{
331
+ type: "text",
332
+ text: error instanceof Error ? error.message : String(error)
333
+ }],
334
+ isError: true
335
+ };
336
+ }
337
+ const WritableFormatSchema = z.enum([
338
+ "docx",
339
+ "pptx",
340
+ "odt",
341
+ "odp",
342
+ "ods",
343
+ "odg",
344
+ "pdf",
345
+ "markdown"
346
+ ]);
347
+ const RunSchema = z.object({
348
+ text: z.string().optional().describe("The run's own text content."),
349
+ bold: z.boolean().optional(),
350
+ italic: z.boolean().optional(),
351
+ strike: z.boolean().optional(),
352
+ underline: z.boolean().optional().describe("docx/odt only."),
353
+ fontFamily: z.string().optional().describe("docx/odt only."),
354
+ sizePt: z.number().positive().optional().describe("docx/odt only."),
355
+ colorHex: z.string().regex(/^#?[0-9a-fA-F]{6}$/).optional().describe("6-digit hex colour (e.g. 'ff0000' or '#ff0000'). docx/odt only."),
356
+ hyperlink: z.string().optional().describe("markdown only."),
357
+ code: z.boolean().optional().describe("markdown only -- renders the run as an inline code span.")
358
+ });
359
+ const ParagraphSchema = z.object({
360
+ text: z.string().optional().describe("Plain paragraph text, as a single run. Omit and use `runs` instead for mixed formatting within one paragraph."),
361
+ styleId: z.string().optional(),
362
+ headingLevel: z.number().int().min(1).max(6).optional().describe("docx/odt only."),
363
+ alignment: z.enum([
364
+ "left",
365
+ "center",
366
+ "right",
367
+ "justify"
368
+ ]).optional().describe("docx/odt only."),
369
+ runs: z.array(RunSchema).optional().describe("Runs to append to this paragraph, each with its own formatting. Combine with `text` for a paragraph that opens with plain text before its first formatted run, or omit `text` entirely for a paragraph built purely from runs.")
370
+ });
371
+ function unsupportedFieldNames(input, unsupported) {
372
+ return unsupported.filter((key) => input[key] !== void 0);
373
+ }
374
+ function rejectUnsupportedFields(input, unsupported, formatLabel, context) {
375
+ const present = unsupportedFieldNames(input, unsupported);
376
+ if (present.length > 0) throw new Error(`${context} does not support ${present.join(", ")} for ${formatLabel} -- remove ${present.length === 1 ? "it" : "them"} or target docx/odt instead.`);
377
+ }
378
+ const DOCX_ODT_UNSUPPORTED_RUN_FIELDS = ["hyperlink", "code"];
379
+ const MARKDOWN_UNSUPPORTED_RUN_FIELDS = [
380
+ "underline",
381
+ "fontFamily",
382
+ "sizePt",
383
+ "colorHex"
384
+ ];
385
+ const MARKDOWN_UNSUPPORTED_PARAGRAPH_FIELDS = ["headingLevel", "alignment"];
386
+ function appendDocxOdtRun(paragraph, run) {
387
+ rejectUnsupportedFields(run, DOCX_ODT_UNSUPPORTED_RUN_FIELDS, "docx/odt", "A run");
388
+ paragraph.appendRun({
389
+ text: run.text,
390
+ bold: run.bold,
391
+ italic: run.italic,
392
+ underline: run.underline,
393
+ strike: run.strike,
394
+ fontFamily: run.fontFamily,
395
+ sizePt: run.sizePt,
396
+ color: run.colorHex === void 0 ? void 0 : rgbHexToColor(run.colorHex)
397
+ });
398
+ }
399
+ function appendDocxOdtParagraphs(body, paragraphs) {
400
+ for (const paragraph of paragraphs) {
401
+ const built = body.appendParagraph({
402
+ text: paragraph.text,
403
+ styleId: paragraph.styleId,
404
+ headingLevel: paragraph.headingLevel,
405
+ alignment: paragraph.alignment
406
+ });
407
+ for (const run of paragraph.runs ?? []) appendDocxOdtRun(built, run);
408
+ }
409
+ }
410
+ function appendMarkdownParagraphs(body, paragraphs) {
411
+ for (const paragraph of paragraphs) {
412
+ rejectUnsupportedFields(paragraph, MARKDOWN_UNSUPPORTED_PARAGRAPH_FIELDS, "markdown", "A paragraph");
413
+ const built = body.appendParagraph({
414
+ text: paragraph.text,
415
+ styleId: paragraph.styleId
416
+ });
417
+ for (const run of paragraph.runs ?? []) {
418
+ rejectUnsupportedFields(run, MARKDOWN_UNSUPPORTED_RUN_FIELDS, "markdown", "A run");
419
+ built.appendRun({
420
+ text: run.text,
421
+ bold: run.bold,
422
+ italic: run.italic,
423
+ strike: run.strike,
424
+ hyperlink: run.hyperlink,
425
+ code: run.code
426
+ });
427
+ }
428
+ }
429
+ }
430
+ function createDocumentBytes(format) {
431
+ switch (format) {
432
+ case "docx": return createDocx().toBytes();
433
+ case "pptx": return createPptx().toBytes();
434
+ case "odt": return createOdt().toBytes();
435
+ case "odp": return createOdp().toBytes();
436
+ case "ods": return createOds().toBytes();
437
+ case "odg": return createOdg().toBytes();
438
+ case "pdf": return createPdf().toBytes();
439
+ case "markdown": return encodeMarkdownText(createMarkdownEditor().toMarkdownText());
440
+ }
441
+ }
442
+ function registerEditorTools(server) {
443
+ server.registerTool("document_create", {
444
+ title: "Create a blank document",
445
+ description: "Creates a fresh, blank document in the given format via documents.js's own live-view editors (createDocx/createOdt/createMarkdownEditor/...), the same construction document_append_paragraphs's own edit calls build on. Returns an empty document with no content -- follow with document_append_paragraphs (docx/odt/markdown) to add text.",
446
+ inputSchema: z.object({
447
+ format: WritableFormatSchema.describe("The format of document to create."),
448
+ output: DocumentOutputSchema.optional().describe("Where to write the created document. Omit entirely to receive the bytes inline, base64-encoded.")
449
+ })
450
+ }, async ({ format, output }) => {
451
+ try {
452
+ const resolvedOutput = await resolveDocumentOutput(createDocumentBytes(format), output ?? {});
453
+ return {
454
+ content: [{
455
+ type: "text",
456
+ text: JSON.stringify(resolvedOutput)
457
+ }],
458
+ structuredContent: resolvedOutput
459
+ };
460
+ } catch (error) {
461
+ return toErrorResult$2(error);
462
+ }
463
+ });
464
+ server.registerTool("document_append_paragraphs", {
465
+ title: "Append paragraphs to a wordprocessing document",
466
+ description: "Appends one or more paragraphs -- each optionally built from several independently-formatted runs -- to the end of a docx, odt, or markdown document, through documents.js's own live-view editors (the same DocxBody.appendParagraph/OdtBody.appendParagraph/MarkdownBody.appendParagraph document-cli's own TUI uses). Does not convert format -- the source document's own format and targetFormat must match. docx and odt share an identical field set (underline, fontFamily, sizePt, colorHex, headingLevel, alignment all supported); markdown supports a different, smaller set (hyperlink, code) and rejects the docx/odt-only fields outright rather than silently dropping them. This covers wordprocessing paragraph/run editing only -- slides, sheets, drawings, tables, lists, and images are a separate, larger editing surface not exposed here yet.",
467
+ inputSchema: z.object({
468
+ source: DocumentInputSchema.describe("The document to append paragraphs to."),
469
+ targetFormat: z.enum([
470
+ "docx",
471
+ "odt",
472
+ "markdown"
473
+ ]).describe("Must match the source document's own format. document_append_paragraphs never converts format."),
474
+ paragraphs: z.array(ParagraphSchema).min(1).describe("The paragraphs to append, in order."),
475
+ output: DocumentOutputSchema.optional().describe("Where to write the edited document. Omit entirely to receive the bytes inline, base64-encoded.")
476
+ })
477
+ }, async ({ source, targetFormat, paragraphs, output }) => {
478
+ try {
479
+ const { bytes, format } = await resolveDocumentInput(source);
480
+ if (format !== targetFormat) throw new Error(`source document is "${format}", but targetFormat is "${targetFormat}" -- document_append_paragraphs never converts format, so the two must match.`);
481
+ let resultBytes;
482
+ if (targetFormat === "markdown") {
483
+ const editor = openMarkdown(decodeMarkdownText(bytes));
484
+ appendMarkdownParagraphs(editor.body, paragraphs);
485
+ resultBytes = encodeMarkdownText(editor.toMarkdownText());
486
+ } else {
487
+ const editor = targetFormat === "docx" ? openDocx(bytes) : openOdt(bytes);
488
+ appendDocxOdtParagraphs(editor.body, paragraphs);
489
+ resultBytes = editor.toBytes();
490
+ }
491
+ const resolvedOutput = await resolveDocumentOutput(resultBytes, output ?? {});
492
+ return {
493
+ content: [{
494
+ type: "text",
495
+ text: JSON.stringify(resolvedOutput)
496
+ }],
497
+ structuredContent: resolvedOutput
498
+ };
499
+ } catch (error) {
500
+ return toErrorResult$2(error);
501
+ }
502
+ });
503
+ }
504
+ //#endregion
327
505
  //#region src/tools/fonts.ts
328
506
  const FontFileInputSchema = z.union([z.object({ path: z.string().describe("Filesystem path to the font file (.ttf/.otf) to read.") }), z.object({ bytesBase64: z.string().describe("Base64-encoded font file bytes.") })]);
329
507
  async function resolveFontFileInput(input) {
@@ -972,6 +1150,7 @@ function createServer() {
972
1150
  registerComputeFormulaTools(server);
973
1151
  registerConvertTools(server);
974
1152
  registerDocxExtrasTools(server);
1153
+ registerEditorTools(server);
975
1154
  registerFontTools(server);
976
1155
  registerFromPackageTools(server);
977
1156
  registerMetadataTools(server);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "document-mcp",
3
- "version": "4.6.24",
3
+ "version": "4.7.0",
4
4
  "description": "MCP (Model Context Protocol) server exposing documents.js's document-conversion, .odb, metadata, and font tooling as MCP tools.",
5
5
  "type": "module",
6
6
  "repository": {
@@ -90,10 +90,10 @@
90
90
  "dependencies": {
91
91
  "@modelcontextprotocol/node": "^2.0.0",
92
92
  "@modelcontextprotocol/server": "^2.0.0",
93
- "document-compute.js": "^1.3.23",
93
+ "document-compute.js": "^1.3.25",
94
94
  "document-outline.js": "^3.5.4",
95
95
  "document-schema.js": "^7.0.0",
96
- "documents.js": "^7.4.0",
96
+ "documents.js": "^7.6.0",
97
97
  "zod": "^4.2.0"
98
98
  },
99
99
  "devDependencies": {