md2x
v0.7.6
Published
Markdown converter (local, no server). Supports Mermaid/Graphviz/Vega/HTML/SVG rendering, math, and code highlighting.
Readme
md2x
Markdown → PDF/DOCX/HTML/Image converter.
Features
- 📦 Supported formats:
pdf,docx,html,png,jpg/jpeg,webp - 🔌 MCP (Model Context Protocol): built-in MCP server
- 🧠 Skills: includes an agent skill at
skills/md2x/SKILL.mdfor repeatable conversions/workflows - 🧩 Custom templates: render
md2xblocks with Vue SFC (.vue) and Svelte 5 (.svelte) templates (plus plain HTML)
CLI Usage
Export to PDF:
npx md2x input.mdExport to DOCX:
npx md2x input.md -f docxExport to HTML:
npx md2x input.md -f htmlExport to PNG:
npx md2x input.md -f png -o output.pngList themes:
npx md2x --list-themesUse a theme:
npx md2x input.md -o output.pdf --theme academicHelp:
npx md2x -hCLI Options
| Option | Alias | Description | Default | Values |
|--------|-------|-------------|---------|--------|
| --help | -h | Show help message | - | - |
| --version | -v | Show version number | - | - |
| --output | -o | Output file path | Input name with format extension | File path |
| --format | -f | Output format | pdf | pdf, docx, html, png, jpg/jpeg, webp |
| --theme | -t | Theme name | default | See --list-themes |
| --diagram-mode | - | HTML/Image diagram rendering mode | live | img, live, none |
| --live-runtime | - | HTML live runtime injection strategy (only when diagramMode: live) | cdn | inline, cdn |
| --live-runtime-url | - | Custom runtime URL when --live-runtime cdn | - | URL |
| --hr-page-break | - | Convert horizontal rules to page breaks | true for PDF/DOCX, false for HTML/Image | true, false |
| --templates-dir | - | Extra template dir for md2x blocks (repeatable; resolved against input dir when relative) | - | Directory path |
| --list-themes | - | List all available themes | - | - |
Diagram Modes (HTML/Image)
live(default): Render diagrams in the browser on load using the md2x live runtime (by default it is embedded into the output HTML; seeliveRuntimebelow)img: Pre-render diagrams as embedded images (offline, stable; no CDN)none: Keep diagram source blocks only (no rendering)
Front Matter Options
When converting a markdown file, you can put options in YAML front matter (the CLI merges front matter with CLI flags; explicit CLI flags win).
Common (All Formats)
---
format: pdf # pdf | docx | html | png | jpg | jpeg | webp
theme: default
hrAsPageBreak: true
------
format: pdf
title: "My Doc" # used for PDF metadata/header templates
pdf:
format: A4 # A4 | Letter | Legal | A3 | A5
landscape: false
margin:
top: 1cm
bottom: 1cm
left: 1cm
right: 1cm
printBackground: true
scale: 1
displayHeaderFooter: false
headerTemplate: "<div style='font-size:10px;width:100%;text-align:center;'><span class='title'></span></div>"
footerTemplate: "<div style='font-size:10px;width:100%;text-align:center;'>Page <span class='pageNumber'></span> / <span class='totalPages'></span></div>"
---DOCX
---
format: docx
theme: default
hrAsPageBreak: true
---HTML
---
format: html
title: "My Doc"
standalone: true # full HTML document (default)
baseTag: true # emit <base href="file://.../"> for resolving relative paths (default)
diagramMode: live # img | live | none
liveRuntime: cdn # inline | cdn (default: cdn). Use "inline" for fully self-contained HTML.
# liveRuntimeUrl: "https://cdn.jsdelivr.net/npm/[email protected]/dist/renderer/" # chunked runtime base URL
cdn: # optional: override CDN URLs (used when diagramMode: live)
mermaid: "https://cdn.jsdelivr.net/npm/[email protected]/dist/mermaid.min.js"
# Template blocks:
vue: "https://unpkg.com/vue@3/dist/vue.global.js"
vueSfcLoader: "https://cdn.jsdelivr.net/npm/vue3-sfc-loader/dist/vue3-sfc-loader.js"
svelteCompiler: "https://esm.sh/svelte@5/compiler"
svelteBase: "https://esm.sh/svelte@5/"
---Image (PNG/JPEG/WebP)
---
format: png
diagramMode: live # or "img" for offline (no CDN)
image:
# selector can be a string or an array of selectors (CSS selector list).
selector:
- 'div.md2x-diagram[data-md2x-diagram-kind="mermaid"]'
- 'div.md2x-diagram[data-md2x-diagram-kind="infographic"]'
# selectorMode: first | each | union | stitch (default: stitch)
# - union: capture the union bounding box (includes in-between page content)
# - stitch: stack matched elements and capture only them (no in-between content)
selectorMode: stitch
selectorGap: 16 # optional: vertical gap (px) between stitched elements
selectorPadding: 8 # optional: padding (px) around the stitched region
split: auto # optional: split very tall output into multiple images
---When image.split produces multiple parts, outputs are written as output.part-001.png, output.part-002.png, ...
Diagram blocks are tagged with data-md2x-diagram-kind so you can target specific types via selectors:
image:
selector: 'div.md2x-diagram[data-md2x-diagram-kind="mermaid"]'
selectorMode: stitchmd2x Template Blocks
Besides diagram blocks (mermaid/dot/vega-lite/infographic), md2x also supports template blocks via:
```md2x
{
type: 'vue', // "vue" | "html" | "svelte"
template: 'example.vue', // or "example.html" / "example.svelte"
data: [{ title: 't', message: 'm' }]
}
```//example.vue
<script setup>
const data = templateData;
</script>
<template>
<div class="my-component">Hello md2x! This is vue template</div>
<div v-for="(item, index) in data" :key="index">
<h2>{{ item.title }}</h2>
<p>{{ item.message }}</p>
</div>
</template>
<style scoped>
.my-component {
color: red;
}
</style><!-- example.svelte (Svelte 5) -->
<script>
const data = templateData;
</script>
<div class="my-component">Hello md2x! This is svelte template</div>
{#each data as item, index}
<div>
<h2>{item.title}</h2>
<p>{item.message}</p>
</div>
{/each}
<style>
.my-component { color: red; }
</style>Config Fields
type:"vue","html", or"svelte"(Svelte 5)template: template file name/path- if you only pass a filename (e.g.
example.vue), it is treated as${type}/${template}(e.g.vue/example.vue)
- if you only pass a filename (e.g.
data: arbitrary JSON-serializable data (injected by replacing thetemplateDataplaceholder)allowTemplateAssets(optional, unsafe): whentrue, allow templates to load extra JS/CSS URLs declared in the template file header:<!-- TemplateConfig: {"assets":{"scripts":["..."],"styles":["..."]}} -->- Useful for UMD/IIFE globals (e.g.
window.dayjs), not npm-styleimport. - Backward compat:
allowCdnis accepted as an alias.
allowScripts(optional, unsafe, html only): when exporting images indiagramMode: "img", setallowScripts: trueto execute inline<script>blocks before rendering to PNG.- not supported:
<script type="module"> - external
<script src="...">is not supported for image rendering (use inline scripts)
- not supported:
Svelte Notes (Svelte 5 + esm.sh)
- Svelte templates are compiled at runtime using the Svelte compiler, loaded from esm.sh via
import(). - This means Svelte template rendering requires network access (even in
diagramMode: "img"), unless you overridecdn.svelteCompiler/cdn.svelteBaseto another ESM CDN that works in your environment. - Templates are expected to be self-contained
.sveltefiles (no preprocessors like TypeScript/Sass, and avoid local relative imports unless you provide an ESM-resolvable URL).
Template Resolution (External Templates)
To load templates from outside, use:
- CLI:
--templates-dir /path/to/templates(repeatable; CLI reads files and passes them astemplates) - Library API: pass
templates: Record<string, string>(you can load files yourself if you want) - Front matter:
templates:supports inline template sources (YAML map)
CDN Overrides (Live Mode)
When exporting HTML/Image with diagramMode: live, you can override CDN URLs in front matter:
cdn:
vue: "https://unpkg.com/vue@3/dist/vue.global.js"
vueSfcLoader: "https://cdn.jsdelivr.net/npm/vue3-sfc-loader/dist/vue3-sfc-loader.js"
svelteCompiler: "https://esm.sh/svelte@5/compiler"
svelteBase: "https://esm.sh/svelte@5/"md2x Skill
This repo also includes a skill for driving md2x from an agent:
- Skill:
skills/md2x/SKILL.md - What it does: guides an agent to run
npx md2x ..., pick formats/themes, and use front matter correctly. - Install (example):
npx skills add larchliu/md2x
or
npx add-skill larchliu/md2xMCP Server (Model Context Protocol)
The md2x CLI includes a built-in MCP server that exposes markdown conversion as MCP tools via stdio transport.
Starting the MCP Server
npx md2x --mcpOr if installed globally:
md2x --mcpAvailable Tools
convert_markdown: Convert markdown files to PDF, DOCX, HTML, or Image formats- Takes a
markdownFilePathparameter - Saves output to the same directory as the source file (or custom
outputPath) - Returns the file path to the converted document
- Takes a
list_themes: List all available themes with their categories and featured status
Integration with Claude Desktop
Add to your Claude Desktop configuration (~/Library/Application Support/Claude/claude_desktop_config.json on macOS):
{
"mcpServers": {
"md2x": {
"command": "node",
"args": ["/path/to/markdown-viewer-extension/node/dist/md2x.js", "--mcp"]
}
}
}Testing
node --test test/mcp-server.test.mjsSee MCP-SERVER.md for detailed documentation.
HTTP-based MCP Server (Separate Package)
There's also a separate Express-based MCP server in the mcp/ directory that exposes md2x as MCP tools over HTTP:
pnpm -C mcp install
pnpm -C mcp startSee mcp/README.md for details.
Puppeteer / Chrome install
This package depends on puppeteer. On first install, Puppeteer downloads a compatible "Chrome for Testing" build (cached under your user directory). Set PUPPETEER_SKIP_DOWNLOAD=1 to skip download and use a system Chrome via PUPPETEER_EXECUTABLE_PATH.
Open Source License
This project is open source under ISC license. Welcome to Star, report issues, suggest features, and contribute code.
Project URL: https://github.com/LarchLiu/md2x
Acknowledgements
- markdown-viewer-extension - Developed based on this project
