document-mcp 2.0.9 → 2.1.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 +7 -1
- package/dist/bin.js +66 -1
- package/dist/index.cjs +66 -1
- package/dist/index.js +66 -1
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -15,9 +15,12 @@ graph TD
|
|
|
15
15
|
mdcodec("markdown-codec")
|
|
16
16
|
bytecodec("byte-codec")
|
|
17
17
|
documents("documents.js")
|
|
18
|
+
outline("document-outline.js")
|
|
18
19
|
mcp("document-mcp")
|
|
19
20
|
cli("document-cli")
|
|
20
21
|
|
|
22
|
+
schema --> outline
|
|
23
|
+
outline --> mcp
|
|
21
24
|
schema --> ooxml
|
|
22
25
|
schema --> odf
|
|
23
26
|
schema --> pdfcodec
|
|
@@ -42,6 +45,7 @@ graph TD
|
|
|
42
45
|
click mdcodec "https://github.com/ExaDev/markdown-codec" "markdown-codec"
|
|
43
46
|
click bytecodec "https://github.com/ExaDev/byte-codec" "byte-codec"
|
|
44
47
|
click documents "https://github.com/ExaDev/documents.js" "documents.js"
|
|
48
|
+
click outline "https://github.com/ExaDev/document-outline.js" "document-outline.js"
|
|
45
49
|
click mcp "https://github.com/ExaDev/document-mcp" "document-mcp"
|
|
46
50
|
click cli "https://github.com/ExaDev/document-cli" "document-cli"
|
|
47
51
|
|
|
@@ -210,6 +214,7 @@ Every tool that takes or produces document bytes goes through the same two hybri
|
|
|
210
214
|
| `pdf_inspect` | Parses a PDF and reports a summary (page count, per-page size and item-kind histogram, metadata, embedded image formats), or the entire parsed `LayoutDocument` with `full: true`. |
|
|
211
215
|
| `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. |
|
|
212
216
|
| `from_package` | Rebuilds real document bytes in a target format from a `DocumentPackage` previously serialised to JSON (e.g. by a conversion tool's own `onDocument`/package-dump step). |
|
|
217
|
+
| `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 content — read through `documents.js`'s `DocumentConverter` port and built by `document-outline.js`'s `buildOutline`. |
|
|
213
218
|
| `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). |
|
|
214
219
|
| `odb_forms` | Lists every form an `.odb` database declares, with each form's own data source and field-bound controls. |
|
|
215
220
|
| `odb_reports` | Lists every report an `.odb` database declares, with each report's own data-source command, band/group structure, and `rpt:` formula expressions. |
|
|
@@ -221,12 +226,13 @@ Every tool that takes or produces document bytes goes through the same two hybri
|
|
|
221
226
|
## References
|
|
222
227
|
|
|
223
228
|
- [documents.js](https://github.com/ExaDev/documents.js) — the library this server exposes.
|
|
229
|
+
- [document-outline.js](https://github.com/ExaDev/document-outline.js) — the artefact-utilities package over document-schema.js's tree-form `DocumentPackage` whose `buildOutline` powers `outline_document`.
|
|
224
230
|
- [document-cli](https://github.com/ExaDev/document-cli) — the sibling CLI/TUI over the same library, whose toolchain this repository's scaffold mirrors.
|
|
225
231
|
- [Model Context Protocol](https://modelcontextprotocol.io) — the protocol this server implements, via [`@modelcontextprotocol/server`](https://www.npmjs.com/package/@modelcontextprotocol/server).
|
|
226
232
|
|
|
227
233
|
## Gotchas
|
|
228
234
|
|
|
229
|
-
- **Runtime dependencies are `documents.js` + `@modelcontextprotocol/server` + `zod` only; `pdf-codec` and `odf.js` are devDependencies (test-support only).** Every runtime reach into
|
|
235
|
+
- **Runtime dependencies are `documents.js` + `document-outline.js` + `@modelcontextprotocol/server` + `zod` only; `pdf-codec` and `odf.js` are devDependencies (test-support only).** `document-outline.js` is the one dependency beyond the server stack itself: `outline_document` imports `buildOutline`/`outlineLeafText` from it, and documents.js deliberately does not re-export them (the outline projection lives in the family's artefact-utilities package, which depends only on `document-schema.js` — already a transitive dependency via documents.js — so it adds no second copy of anything). Every runtime reach into `pdf-codec`/`odf.js` — `ProvidedFont`/`FontSubstitution`/`describeFontFace`/the `WinAnsi` substitution shape — goes through `documents.js`'s own re-exports, so a published install pulls in no direct `pdf-codec`/`odf.js` dependency. `odf.js` survives in `devDependencies` solely because `src/test-support/odm-fixture.ts` and `src/test-support/embedded-font-fixture.ts` build real ODF package fixtures from its low-level XML primitives (`zipPackage`/`el`/`rootElement`), and `src/test-support/` is excluded from the `tsdown` build — only `src/index.ts` and `src/bin.ts` are entry points — so neither fixture module ever ships in `dist/`.
|
|
230
236
|
|
|
231
237
|
## License
|
|
232
238
|
|
package/dist/bin.js
CHANGED
|
@@ -6,8 +6,9 @@ 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
|
+
import { buildOutline, isOutlineNode, outlineLeafText } from "document-outline.js";
|
|
9
10
|
//#region package.json
|
|
10
|
-
var version = "2.0
|
|
11
|
+
var version = "2.1.0";
|
|
11
12
|
//#endregion
|
|
12
13
|
//#region src/io/document-input.ts
|
|
13
14
|
const EXTENSION_TO_FORMAT = {
|
|
@@ -773,6 +774,69 @@ function registerOdmTools(server) {
|
|
|
773
774
|
});
|
|
774
775
|
}
|
|
775
776
|
//#endregion
|
|
777
|
+
//#region src/tools/outline.ts
|
|
778
|
+
const OUTLINE_PROBE_TARGETS = {
|
|
779
|
+
csv: "ods",
|
|
780
|
+
docx: "odt",
|
|
781
|
+
odf: "pdf",
|
|
782
|
+
odg: "pdf",
|
|
783
|
+
odt: "docx",
|
|
784
|
+
odp: "pptx",
|
|
785
|
+
ods: "xlsx",
|
|
786
|
+
markdown: "docx",
|
|
787
|
+
pdf: "docx",
|
|
788
|
+
pptx: "odp",
|
|
789
|
+
svg: "odg",
|
|
790
|
+
xlsx: "ods"
|
|
791
|
+
};
|
|
792
|
+
function leafKind(leaf) {
|
|
793
|
+
if ("kind" in leaf) return leaf.kind;
|
|
794
|
+
if ("mathml" in leaf) return "formula";
|
|
795
|
+
return "embeddedObject";
|
|
796
|
+
}
|
|
797
|
+
function toOutlineJson(children) {
|
|
798
|
+
return children.map((child) => isOutlineNode(child) ? {
|
|
799
|
+
text: child.text,
|
|
800
|
+
level: child.level,
|
|
801
|
+
children: toOutlineJson(child.children)
|
|
802
|
+
} : {
|
|
803
|
+
kind: leafKind(child),
|
|
804
|
+
text: outlineLeafText(child)
|
|
805
|
+
});
|
|
806
|
+
}
|
|
807
|
+
function registerOutlineTools(server) {
|
|
808
|
+
const converter = createLocalDocumentConverter();
|
|
809
|
+
server.registerTool("outline_document", {
|
|
810
|
+
title: "Outline document",
|
|
811
|
+
description: "Projects a document's table of contents as a structured outline: reads the source through documents.js's DocumentConverter port, takes the tree-form DocumentPackage the conversion reports, and runs document-outline.js's buildOutline over it. Groups carry { text, level, children } (a heading's, list item's, slide's, sheet's, or page's own label plus nested children); leaves carry { kind, text }. The outline is over the source's own content -- the internal conversion target preserves it and is pdf only for odf (the one format that only converts to pdf) and odg (whose alternative, svg, cannot represent more than one page).",
|
|
812
|
+
inputSchema: z.object({ source: DocumentInputSchema.describe("The document to outline.") })
|
|
813
|
+
}, async ({ source }, ctx) => {
|
|
814
|
+
const { signal } = ctx.mcpReq;
|
|
815
|
+
const { bytes, format } = await resolveDocumentInput(source, { signal });
|
|
816
|
+
const targetFormat = OUTLINE_PROBE_TARGETS[format];
|
|
817
|
+
const pkg = (await converter.convert({
|
|
818
|
+
source: {
|
|
819
|
+
format,
|
|
820
|
+
bytes
|
|
821
|
+
},
|
|
822
|
+
targetFormat
|
|
823
|
+
}, { signal })).package;
|
|
824
|
+
if (pkg === void 0) throw new Error(`the ${format}-to-${targetFormat} conversion reported no DocumentPackage, so there is no tree to outline`);
|
|
825
|
+
const structuredContent = {
|
|
826
|
+
sourceFormat: format,
|
|
827
|
+
kind: pkg.kind,
|
|
828
|
+
outline: toOutlineJson(buildOutline(pkg))
|
|
829
|
+
};
|
|
830
|
+
return {
|
|
831
|
+
content: [{
|
|
832
|
+
type: "text",
|
|
833
|
+
text: JSON.stringify(structuredContent)
|
|
834
|
+
}],
|
|
835
|
+
structuredContent
|
|
836
|
+
};
|
|
837
|
+
});
|
|
838
|
+
}
|
|
839
|
+
//#endregion
|
|
776
840
|
//#region src/tools/pdf-inspect.ts
|
|
777
841
|
function buildItemKindHistogram(items) {
|
|
778
842
|
const histogram = /* @__PURE__ */ new Map();
|
|
@@ -838,6 +902,7 @@ function createServer() {
|
|
|
838
902
|
registerOdbTools(server);
|
|
839
903
|
registerOdbRenderReportTools(server);
|
|
840
904
|
registerOdmTools(server);
|
|
905
|
+
registerOutlineTools(server);
|
|
841
906
|
registerPdfInspectTools(server);
|
|
842
907
|
return server;
|
|
843
908
|
}
|
package/dist/index.cjs
CHANGED
|
@@ -5,8 +5,9 @@ let zod = require("zod");
|
|
|
5
5
|
let node_fs_promises = require("node:fs/promises");
|
|
6
6
|
let node_fs = require("node:fs");
|
|
7
7
|
let node_path = require("node:path");
|
|
8
|
+
let document_outline_js = require("document-outline.js");
|
|
8
9
|
//#region package.json
|
|
9
|
-
var version = "2.0
|
|
10
|
+
var version = "2.1.0";
|
|
10
11
|
//#endregion
|
|
11
12
|
//#region src/io/document-input.ts
|
|
12
13
|
const EXTENSION_TO_FORMAT = {
|
|
@@ -772,6 +773,69 @@ function registerOdmTools(server) {
|
|
|
772
773
|
});
|
|
773
774
|
}
|
|
774
775
|
//#endregion
|
|
776
|
+
//#region src/tools/outline.ts
|
|
777
|
+
const OUTLINE_PROBE_TARGETS = {
|
|
778
|
+
csv: "ods",
|
|
779
|
+
docx: "odt",
|
|
780
|
+
odf: "pdf",
|
|
781
|
+
odg: "pdf",
|
|
782
|
+
odt: "docx",
|
|
783
|
+
odp: "pptx",
|
|
784
|
+
ods: "xlsx",
|
|
785
|
+
markdown: "docx",
|
|
786
|
+
pdf: "docx",
|
|
787
|
+
pptx: "odp",
|
|
788
|
+
svg: "odg",
|
|
789
|
+
xlsx: "ods"
|
|
790
|
+
};
|
|
791
|
+
function leafKind(leaf) {
|
|
792
|
+
if ("kind" in leaf) return leaf.kind;
|
|
793
|
+
if ("mathml" in leaf) return "formula";
|
|
794
|
+
return "embeddedObject";
|
|
795
|
+
}
|
|
796
|
+
function toOutlineJson(children) {
|
|
797
|
+
return children.map((child) => (0, document_outline_js.isOutlineNode)(child) ? {
|
|
798
|
+
text: child.text,
|
|
799
|
+
level: child.level,
|
|
800
|
+
children: toOutlineJson(child.children)
|
|
801
|
+
} : {
|
|
802
|
+
kind: leafKind(child),
|
|
803
|
+
text: (0, document_outline_js.outlineLeafText)(child)
|
|
804
|
+
});
|
|
805
|
+
}
|
|
806
|
+
function registerOutlineTools(server) {
|
|
807
|
+
const converter = (0, documents_js.createLocalDocumentConverter)();
|
|
808
|
+
server.registerTool("outline_document", {
|
|
809
|
+
title: "Outline document",
|
|
810
|
+
description: "Projects a document's table of contents as a structured outline: reads the source through documents.js's DocumentConverter port, takes the tree-form DocumentPackage the conversion reports, and runs document-outline.js's buildOutline over it. Groups carry { text, level, children } (a heading's, list item's, slide's, sheet's, or page's own label plus nested children); leaves carry { kind, text }. The outline is over the source's own content -- the internal conversion target preserves it and is pdf only for odf (the one format that only converts to pdf) and odg (whose alternative, svg, cannot represent more than one page).",
|
|
811
|
+
inputSchema: zod.z.object({ source: DocumentInputSchema.describe("The document to outline.") })
|
|
812
|
+
}, async ({ source }, ctx) => {
|
|
813
|
+
const { signal } = ctx.mcpReq;
|
|
814
|
+
const { bytes, format } = await resolveDocumentInput(source, { signal });
|
|
815
|
+
const targetFormat = OUTLINE_PROBE_TARGETS[format];
|
|
816
|
+
const pkg = (await converter.convert({
|
|
817
|
+
source: {
|
|
818
|
+
format,
|
|
819
|
+
bytes
|
|
820
|
+
},
|
|
821
|
+
targetFormat
|
|
822
|
+
}, { signal })).package;
|
|
823
|
+
if (pkg === void 0) throw new Error(`the ${format}-to-${targetFormat} conversion reported no DocumentPackage, so there is no tree to outline`);
|
|
824
|
+
const structuredContent = {
|
|
825
|
+
sourceFormat: format,
|
|
826
|
+
kind: pkg.kind,
|
|
827
|
+
outline: toOutlineJson((0, document_outline_js.buildOutline)(pkg))
|
|
828
|
+
};
|
|
829
|
+
return {
|
|
830
|
+
content: [{
|
|
831
|
+
type: "text",
|
|
832
|
+
text: JSON.stringify(structuredContent)
|
|
833
|
+
}],
|
|
834
|
+
structuredContent
|
|
835
|
+
};
|
|
836
|
+
});
|
|
837
|
+
}
|
|
838
|
+
//#endregion
|
|
775
839
|
//#region src/tools/pdf-inspect.ts
|
|
776
840
|
function buildItemKindHistogram(items) {
|
|
777
841
|
const histogram = /* @__PURE__ */ new Map();
|
|
@@ -837,6 +901,7 @@ function createServer() {
|
|
|
837
901
|
registerOdbTools(server);
|
|
838
902
|
registerOdbRenderReportTools(server);
|
|
839
903
|
registerOdmTools(server);
|
|
904
|
+
registerOutlineTools(server);
|
|
840
905
|
registerPdfInspectTools(server);
|
|
841
906
|
return server;
|
|
842
907
|
}
|
package/dist/index.js
CHANGED
|
@@ -4,8 +4,9 @@ import { z } from "zod";
|
|
|
4
4
|
import { readFile, writeFile } from "node:fs/promises";
|
|
5
5
|
import { existsSync, readFileSync } from "node:fs";
|
|
6
6
|
import { basename, join } from "node:path";
|
|
7
|
+
import { buildOutline, isOutlineNode, outlineLeafText } from "document-outline.js";
|
|
7
8
|
//#region package.json
|
|
8
|
-
var version = "2.0
|
|
9
|
+
var version = "2.1.0";
|
|
9
10
|
//#endregion
|
|
10
11
|
//#region src/io/document-input.ts
|
|
11
12
|
const EXTENSION_TO_FORMAT = {
|
|
@@ -771,6 +772,69 @@ function registerOdmTools(server) {
|
|
|
771
772
|
});
|
|
772
773
|
}
|
|
773
774
|
//#endregion
|
|
775
|
+
//#region src/tools/outline.ts
|
|
776
|
+
const OUTLINE_PROBE_TARGETS = {
|
|
777
|
+
csv: "ods",
|
|
778
|
+
docx: "odt",
|
|
779
|
+
odf: "pdf",
|
|
780
|
+
odg: "pdf",
|
|
781
|
+
odt: "docx",
|
|
782
|
+
odp: "pptx",
|
|
783
|
+
ods: "xlsx",
|
|
784
|
+
markdown: "docx",
|
|
785
|
+
pdf: "docx",
|
|
786
|
+
pptx: "odp",
|
|
787
|
+
svg: "odg",
|
|
788
|
+
xlsx: "ods"
|
|
789
|
+
};
|
|
790
|
+
function leafKind(leaf) {
|
|
791
|
+
if ("kind" in leaf) return leaf.kind;
|
|
792
|
+
if ("mathml" in leaf) return "formula";
|
|
793
|
+
return "embeddedObject";
|
|
794
|
+
}
|
|
795
|
+
function toOutlineJson(children) {
|
|
796
|
+
return children.map((child) => isOutlineNode(child) ? {
|
|
797
|
+
text: child.text,
|
|
798
|
+
level: child.level,
|
|
799
|
+
children: toOutlineJson(child.children)
|
|
800
|
+
} : {
|
|
801
|
+
kind: leafKind(child),
|
|
802
|
+
text: outlineLeafText(child)
|
|
803
|
+
});
|
|
804
|
+
}
|
|
805
|
+
function registerOutlineTools(server) {
|
|
806
|
+
const converter = createLocalDocumentConverter();
|
|
807
|
+
server.registerTool("outline_document", {
|
|
808
|
+
title: "Outline document",
|
|
809
|
+
description: "Projects a document's table of contents as a structured outline: reads the source through documents.js's DocumentConverter port, takes the tree-form DocumentPackage the conversion reports, and runs document-outline.js's buildOutline over it. Groups carry { text, level, children } (a heading's, list item's, slide's, sheet's, or page's own label plus nested children); leaves carry { kind, text }. The outline is over the source's own content -- the internal conversion target preserves it and is pdf only for odf (the one format that only converts to pdf) and odg (whose alternative, svg, cannot represent more than one page).",
|
|
810
|
+
inputSchema: z.object({ source: DocumentInputSchema.describe("The document to outline.") })
|
|
811
|
+
}, async ({ source }, ctx) => {
|
|
812
|
+
const { signal } = ctx.mcpReq;
|
|
813
|
+
const { bytes, format } = await resolveDocumentInput(source, { signal });
|
|
814
|
+
const targetFormat = OUTLINE_PROBE_TARGETS[format];
|
|
815
|
+
const pkg = (await converter.convert({
|
|
816
|
+
source: {
|
|
817
|
+
format,
|
|
818
|
+
bytes
|
|
819
|
+
},
|
|
820
|
+
targetFormat
|
|
821
|
+
}, { signal })).package;
|
|
822
|
+
if (pkg === void 0) throw new Error(`the ${format}-to-${targetFormat} conversion reported no DocumentPackage, so there is no tree to outline`);
|
|
823
|
+
const structuredContent = {
|
|
824
|
+
sourceFormat: format,
|
|
825
|
+
kind: pkg.kind,
|
|
826
|
+
outline: toOutlineJson(buildOutline(pkg))
|
|
827
|
+
};
|
|
828
|
+
return {
|
|
829
|
+
content: [{
|
|
830
|
+
type: "text",
|
|
831
|
+
text: JSON.stringify(structuredContent)
|
|
832
|
+
}],
|
|
833
|
+
structuredContent
|
|
834
|
+
};
|
|
835
|
+
});
|
|
836
|
+
}
|
|
837
|
+
//#endregion
|
|
774
838
|
//#region src/tools/pdf-inspect.ts
|
|
775
839
|
function buildItemKindHistogram(items) {
|
|
776
840
|
const histogram = /* @__PURE__ */ new Map();
|
|
@@ -836,6 +900,7 @@ function createServer() {
|
|
|
836
900
|
registerOdbTools(server);
|
|
837
901
|
registerOdbRenderReportTools(server);
|
|
838
902
|
registerOdmTools(server);
|
|
903
|
+
registerOutlineTools(server);
|
|
839
904
|
registerPdfInspectTools(server);
|
|
840
905
|
return server;
|
|
841
906
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "document-mcp",
|
|
3
|
-
"version": "2.0
|
|
3
|
+
"version": "2.1.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": {
|
|
@@ -85,7 +85,8 @@
|
|
|
85
85
|
"packageManager": "pnpm@11.6.0",
|
|
86
86
|
"dependencies": {
|
|
87
87
|
"@modelcontextprotocol/server": "^2.0.0",
|
|
88
|
-
"
|
|
88
|
+
"document-outline.js": "^1.0.0",
|
|
89
|
+
"documents.js": "^3.1.2",
|
|
89
90
|
"zod": "^4.2.0"
|
|
90
91
|
},
|
|
91
92
|
"devDependencies": {
|