document-mcp

中文文档
4.14.204发布于 2026/11/03MITTypeScriptESM + CJS构建来源已验证

MCP (Model Context Protocol) server exposing documents.js's document-conversion, .odb, metadata, and font tooling as MCP tools.

原始使用文档
文档目录17 节
  1. Getting started
  2. Compatibility
  3. Connecting from Claude Code
  4. Connecting from Codex CLI
  5. Connecting from OpenCode
  6. Connecting from Claude Desktop
  7. Connecting from Claude Team/Enterprise (organization)
  8. Remote transport (HTTP)
  9. Standalone binary
  10. Container image
  11. Development
  12. Document I/O
  13. Tools
  14. References
  15. Gotchas
  16. Contributing
  17. License

document-mcp

GitHub npm npm version CI

An MCP (Model Context Protocol) server exposing documents.js's document-conversion, .odb, metadata, and font tooling — plus document-compute.js's units-typed formula evaluation — as MCP tools, so an MCP-speaking agent can convert, inspect, edit, and compute over docx/pptx/odt/odp/ods/odg/odf/pdf/odb/xlsx/markdown documents without writing TypeScript against either library directly.

document-mcp adds no conversion or editing logic of its own — every tool is a thin registerOperation() wrapper (src/register-operation.ts) around a document-operations DocumentOperation: that package holds the actual dispatch to documents.js's conversion functions, DocumentConverter port, and .odb/PDF readers, as one Zod schema plus one transport-agnostic run() per operation, shared with (eventually) a REST server and document-cli's own flag parsing rather than defined here a second time. document-cli is the sibling frontend over the identical underlying operations — a terminal CLI/TUI rather than an MCP server — so the two are independent consumers of one shared implementation and can expose different subsets of it. A convert_document call's fidelity — which (source, targetFormat) pairs round-trip losslessly, which are a best-effort reconstruction, and why — is exactly what documents.js's own Fidelity section documents, table included; it is not restated here.

graph TD
    schema("document-schema.js")
    ooxml("ooxml.js")
    odf("odf.js")
    pdfcodec("pdf-codec")
    mdcodec("markdown-codec")
    bytecodec("byte-codec")
    documents("documents.js")
    outline("document-outline.js")
    compute("document-compute.js")
    operations("document-operations")
    mcp("document-mcp")
    cli("document-cli")

    schema --> outline
    schema --> compute
    schema --> mcp
    schema --> ooxml
    schema --> odf
    schema --> pdfcodec
    schema --> mdcodec
    schema --> documents
    ooxml --> documents
    odf --> documents
    pdfcodec --> documents
    mdcodec --> documents
    bytecodec --> pdfcodec
    bytecodec --> documents
    documents --> operations
    outline --> operations
    compute --> operations
    operations --> mcp
    documents --> cli
    odf --> cli
    pdfcodec --> cli

    click schema "https://github.com/ExaDev/documents.js/tree/main/packages/document-schema.js" "document-schema.js"
    click ooxml "https://github.com/ExaDev/documents.js/tree/main/packages/ooxml.js" "ooxml.js"
    click odf "https://github.com/ExaDev/documents.js/tree/main/packages/odf.js" "odf.js"
    click pdfcodec "https://github.com/ExaDev/documents.js/tree/main/packages/pdf-codec" "pdf-codec"
    click mdcodec "https://github.com/ExaDev/documents.js/tree/main/packages/markdown-codec" "markdown-codec"
    click bytecodec "https://github.com/ExaDev/documents.js/tree/main/packages/byte-codec" "byte-codec"
    click documents "https://github.com/ExaDev/documents.js" "documents.js"
    click outline "https://github.com/ExaDev/documents.js/tree/main/packages/document-outline.js" "document-outline.js"
    click compute "https://github.com/ExaDev/documents.js/tree/main/packages/document-compute.js" "document-compute.js"
    click operations "https://github.com/ExaDev/documents.js/tree/main/packages/document-operations" "document-operations"
    click mcp "https://github.com/ExaDev/documents.js/tree/main/packages/document-mcp" "document-mcp"
    click cli "https://github.com/ExaDev/documents.js/tree/main/packages/document-cli" "document-cli"

    style mcp fill:#f9a825,stroke:#333,stroke-width:3px

Getting started

Run the server directly — no install step needed:

npx document-mcp

The server uses stdio transport (runs as a local process). This is supported by Claude Code, Claude Desktop, Codex CLI, Codex Desktop, and OpenCode directly. Claude Web (claude.ai), Claude Mobile, and ChatGPT require a remote HTTP MCP server — see Remote transport below.

Compatibility

ClientTransportDirect support
Claude Code (CLI)stdio✅
Claude Code (plugin)stdio✅
Claude Desktopstdio✅
Codex CLIstdio✅
Codex Desktopstdio✅
OpenCodestdio✅
Claude Team/Enterprise (org)stdio (per-machine)✅ via managed settings
Claude Web (claude.ai)HTTP/SSE only❌ needs remote transport
Claude Mobile (iOS/Android)HTTP/SSE only❌ needs remote transport
ChatGPT (web/desktop)HTTP only❌ needs remote transport

Connecting from Claude Code

One-liner (adds the MCP server directly):

claude mcp add --transport stdio document-mcp — npx -y document-mcp

Or install as a Claude Code plugin (this repo is a plugin marketplace — includes auto-update on new releases):

From the terminal:

claude plugin marketplace add ExaDev/document-mcp
claude plugin install document-mcp@exadev

Or from within a running Claude Code session:

/plugin marketplace add ExaDev/document-mcp
/plugin install document-mcp@exadev

Run /reload-plugins to activate in an already-running session. In Claude Desktop or on claude.ai: Customize → Plugins → Browse plugins, search for document-mcp, and install.

Connecting from Codex CLI

codex mcp add document-mcp — npx -y document-mcp

Or via the Codex Desktop app: Settings → MCP Servers → + Add.

Or add to ~/.codex/config.toml manually:

[mcp_servers.document-mcp]
command = "npx"
args = ["-y", "document-mcp"]

Connecting from OpenCode

Add to opencode.json:

{
  "mcp": {
    "document-mcp": {
      "type": "local",
      "command": ["npx", "-y", "document-mcp"]
    }
  }
}

Connecting from Claude Desktop

Add to the mcpServers block in Claude Desktop's config file (~/Library/Application Support/Claude/claude_desktop_config.json on macOS):

{
  "mcpServers": {
    "document-mcp": {
      "command": "npx",
      "args": ["-y", "document-mcp"]
    }
  }
}

Or, for local development against a checkout of this repository rather than the published package, point command at the built binary directly:

{
  "mcpServers": {
    "document-mcp": {
      "command": "node",
      "args": ["/absolute/path/to/document-mcp/dist/bin.js"]
    }
  }
}

Connecting from Claude Team/Enterprise (organization)

Organization admins can deploy MCP server configurations centrally via server-managed settings (Admin Settings → Claude Code → Managed settings in the claude.ai console). A managed-settings.json entry for document-mcp enforces the connection across all Claude Code users in the org — no per-user setup needed. Admins can also allow/block specific MCP servers via allowedMcpServers/blockedMcpServers in the same file.

Remote transport (HTTP)

Claude Web, Claude Mobile, and ChatGPT only accept remote (HTTP/SSE) MCP servers — a local stdio process is not reachable from a browser or phone. To use document-mcp on those platforms, run it behind an HTTP transport:

npx document-mcp --transport http --port 3000

This starts a real Streamable HTTP listener bound to 127.0.0.1 (loopback only) on the given --port (default 3000), serving the identical tool set the stdio transport registers — one MCP server instance per request, built from the same createServer() factory. --port 0 asks the OS for a free port; the server reports the port it actually bound on stderr before serving requests. It answers on /mcp and 404s everywhere else; a request from an older HTTP+SSE-era client is served transparently alongside current clients on that same endpoint, so there is no separate --transport sse to choose.

Then add the server URL (e.g., https://your-host:3000/mcp) as a connector in Claude Web (claude.ai/customize/connectors) or ChatGPT (Settings → Connectors → Advanced → Enable Developer Mode → Create). Use a tunnel (Cloudflare Tunnel, ngrok) or deploy to a server with TLS — both platforms require HTTPS; loopback-only binding means the tunnel or reverse proxy must run on the same host as document-mcp itself.

Security note: this HTTP listener has no authentication and no Host/Origin allowlisting of its own — anyone who can reach it can call every tool, including ones that read and write arbitrary filesystem paths. It is safe by default only because it binds to loopback; whatever fronts it for remote access (tunnel, reverse proxy) is responsible for authenticating callers before traffic ever reaches this process.

Standalone binary

Every release also attaches a Node single-executable application build for Linux (x64 and arm64), Windows (x64 and arm64), and macOS (Apple Silicon and Intel) to that release's own GitHub Release assets — the entire server and its dependencies embedded in one file, needing no Node.js install or npx at all. It supports both stdio and --transport http exactly as above; point an MCP client's command at the downloaded binary directly instead of npx/node. Download the asset matching your platform from the package's tag on the Releases page and run it directly (chmod +x on Linux/macOS first).

Container image

Every release also publishes a multi-arch (linux/amd64 + linux/arm64) container image to GitHub Container Registry, wrapping the identical standalone --transport http binary above on a minimal distroless base rather than a Node install:

docker run -p 3000:3000 ghcr.io/exadev/document-mcp:VERSION --port 3000

The image always runs in --transport http mode — stdio mode is exec'd directly by an MCP client as a subprocess, which a container has no role in — and binds to 0.0.0.0 inside the container regardless of --port, so -p <host>:<container> reaches /mcp directly. Replace VERSION with the package's own exact release version; latest also tracks the newest release, matching document-rest's identical image. See Remote transport above for this listener's own lack of authentication.

Development

Requires Node.js >=20 and pnpm 11.6.0 (pinned via packageManager in package.json).

pnpm install
pnpm build         # turbo -> tsdown -> dist/ (ESM + CJS + .d.ts)
pnpm typecheck     # turbo -> tsc --noEmit
pnpm lint          # turbo -> eslint . --fix --cache --max-warnings 0
pnpm test          # turbo -> vitest run --project unit
pnpm test:workers  # turbo -> vitest under the real Cloudflare Workers runtime (workerd) via @cloudflare/vitest-pool-workers, driving createServer() through an in-memory JSON-RPC pair
pnpm test:smoke    # turbo -> tsdown then vitest --project smoke — spawns dist/bin.js as a real subprocess driven over genuine MCP stdio

Document I/O

Every tool that takes or produces document bytes goes through the same two hybrid shapes, documented once here rather than repeated per tool below.

Input (DocumentInput) is a union: either a filesystem path (the format is inferred from the file extension — docx, pptx, xlsx, odt, odp, ods, odg, odf, md/markdown, pdf), or inline bytesBase64 plus an explicit format (required, since inline bytes carry no filename to infer one from). Each ODF/OOXML template and macro-enabled variant also reads as its base format: .ott/.ots/.otp/.otg/.otf as odt/ods/odp/odg/odf, and .dotx/.potx/.xltx (templates) or .docm/.xlsm/.pptm (macro-enabled) as their OOXML base — a template is the same package with a -template mimetype, and a macro-enabled file carries a vbaProject part this library reads past without executing or re-emitting. .odb tools are the one exception: a .odb has no single DocumentFormat of its own (it is a database front end, not a document — tables, saved queries, and reports are three unrelated output shapes), so their source.path/source.bytesBase64 bytes are read directly with no format inference at all.

Output (DocumentOutput), on every tool that produces a document, is a single optional outputPath: supply it to have the tool write the result to that filesystem path (the response then reports { path, byteLength }); omit it to receive the bytes inline instead ({ bytesBase64, byteLength }, flagged large: true above 5 MB — advisory only, the bytes are never truncated or refused).

Tools

ToolDescription
convert_documentConverts a document from one supported format to another via documents.js's DocumentConverter port — docx, pptx, xlsx, odt, odp, ods, odg, odf, markdown, rtf, wpd, doc, xls, ppt, epub, csv, svg, and pdf. Not every (source, targetFormat) pair is direct; call list_document_conversions first.
list_document_conversionsLists every (source, target) format pair convert_document actually supports.
metadata_readReads a document's title/author/subject/keywords/creator/producer/created-and-modified timestamps. Works across every supported format, including xlsx and odf.
metadata_writePatches 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.
document_createCreates a fresh, blank document via documents.js's own live-view editors (createDocx/createOdt/createMarkdownEditor/...) — docx, pptx, odt, odp, ods, odg, pdf, or markdown.
document_append_paragraphsAppends 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.
fontsLists every source-embedded font face a docx/pptx/odt/odp/ods/odg document carries (family, weight/style, byte length).
describe_font_fileReads a standalone .ttf/.otf font file and reports the family/bold/italic triple it declares about itself.
docx_extrasReads a docx's own comments, footnotes, header/footer parts, and numbering definitions — data the ContentDocument pivot cannot carry, so no other tool sees it.
pdf_inspectParses 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.
odm_to_pdfConverts 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.
from_packageRebuilds 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.
outline_documentProjects 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.
compute_formulaReads 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.
odb_tablesLists 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).
odb_formsLists every form an .odb database declares, with each form's own data source and field-bound controls.
odb_reportsLists every report an .odb database declares, with each report's own data-source command, band/group structure, and rpt: formula expressions.
odb_queryRuns a bounded SELECT (with optional JOINs of any kind, table aliases, a derived table in FROM, and IN/EXISTS subqueries) over an embedded .odb database's extracted tables — given directly as SQL or by naming a saved query. No database engine involved; no column aliases; an unsupported construct is reported as a tool error naming it, never silently ignored.
odb_to_csvExtracts 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.
odb_to_xlsxExtracts every table an embedded .odb database declares into one xlsx workbook, one sheet per table.
odb_render_reportResolves 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.

References

Gotchas

  • Runtime dependencies are document-operations + documents.js + @modelcontextprotocol/server + @modelcontextprotocol/node + zod only; pdf-codec, odf.js, and document-schema.js are devDependencies (test-support only). @modelcontextprotocol/node is the Node adapter (toNodeHandler) the --transport http listener uses to bridge @modelcontextprotocol/server's web-standard createMcpHandler onto a plain node:http server — see Remote transport above. Every tool's actual implementation — the conversion/editing/inspection/.odb logic previously defined directly in src/tools/*.ts, including its own reach into document-outline.js's buildOutline/outlineLeafText and document-compute.js's evaluate() — now lives in document-operations as a DocumentOperation; this package's own src/tools/*.ts are thin registerOperation() wrappers (src/register-operation.ts) that register each one as an MCP tool and, for the two operations whose own errors need MCP-specific enrichment (odb_render_report's OdbReportNotSpecifiedError, odm_to_pdf's OdmUnresolvedSectionError), a mapError hook. Every runtime reach into pdf-codec/odf.js — ProvidedFont/FontSubstitution/describeFontFace/the WinAnsi substitution shape — goes through documents.js's own re-exports (by way of document-operations), so a published install pulls in no direct pdf-codec/odf.js dependency. odf.js and document-schema.js survive in devDependencies solely for this package's own test fixtures and compute_formula's own test assertions (document-schema.js's assembleTree/ContentDocument); src/test-support/ is excluded from the tsdown build — only src/index.ts and src/bin.ts are entry points — so none of it ever ships in dist/.

Contributing

Release, CI, and commit-message conventions are all workspace-wide, not package-local — see the monorepo root README for the release mechanism and CONTRIBUTING.md for the shared git hooks and history conventions. Work inside packages/document-mcp/.

License

MIT

版本与发布记录

document-mcp 共发布 540 个版本,首次发布于 2026/08/04;过去 12 个月发布了 540 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
4.14.204latest2026/11/03今天
4.14.2032026/10/313 天前
4.14.2022026/10/313 天前
4.14.2012026/10/313 天前
4.14.2002026/10/313 天前
4.14.1992026/10/313 天前

关于 document-mcp 的常见问题

document-mcp 是什么?

MCP(模型上下文协议)服务器公开documents.js的文档转换。odb、元数据和字体工具作为MCP工具。

如何安装 document-mcp?

在项目目录运行 npm install document-mcp,或使用 pnpm add / yarn add / bun add。它还提供命令行工具 document-mcp,可以用 npx document-mcp 直接运行。

document-mcp 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

document-mcp 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

document-mcp 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=20。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

document-mcp 可以商用吗?

document-mcp 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

document-mcp 还在维护吗?

最新版本 4.14.204 发布于 2026/11/03(今天);至今共发布 540 个版本,其中过去 12 个月发布了 540 个;首次发布于 2026/08/04。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。