MCP server for publication-quality A4 PDF typesetting from Markdown
Project description
Markdown Publishing MCP
md-publishing-mcp is an MCP server that converts Markdown into publication-quality A4 PDF documents through a 4-layer typesetting pipeline.
What It Is
Most Markdown-to-PDF tools are simple converters. They pipe Markdown through Pandoc or an HTML renderer and call it done. Tables break across pages awkwardly. Code blocks overflow margins. Widow and orphan lines go unchecked. Headers and footers are an afterthought.
This project takes a different approach. It treats document generation as a typesetting problem, not a conversion problem. Markdown is parsed into an abstract syntax tree, normalized into an intermediate representation (IR), composed through typographic rules, and finally compiled into a PDF using the Typst engine. The result is a professional document with proper page control, consistent spacing, and reliable layout.
Features
- Professional A4 typesetting. A full typesetting pipeline with widow/orphan prevention, keep-with-next heading rules, and precise page-break control.
- 4-layer architecture. Markdown Parser → Document IR → Typst Generator → PDF Renderer. Each layer is independently testable and replaceable.
- Cache-based preview. Render once, preview individual pages from cache without recompiling.
- Concurrent request handling. Semaphore-based render pool limits concurrent Typst compilations (default: 3), with queuing for additional requests.
- Secure input validation. Path traversal prevention on image and link references, URL protocol filtering (blocks
javascript:,file:,data:), input size limits, and schema validation with Pydantic. - Template system. Multiple presets (default, modern, classic, minimal) with customizable paper size and margins.
- Rich content support. Tables with automatic page-splitting and landscape orientation, code blocks with syntax highlighting and break prevention, images (embedded, local, remote URL), blockquotes, lists, and horizontal rules.
Architecture
Input Markdown
|
v
[Layer 1] Markdown Parser (markdown-it-py)
| DocumentIR
v
[Layer 2] IR Builder + Composition Engine
| ComposedDocument
v
[Layer 3] Typst Generator + Template Manager
| .typ source
v
[Layer 4] PDF Renderer (typst CLI)
| PDF bytes + cache
v
Output PDF
Layer 1: Markdown Parser. Uses markdown-it-py to parse Markdown into a structured IR (DocumentIR). Handles all Markdown syntax variants (CommonMark + GFM tables).
Layer 2: IR Builder & Composition Engine. Normalizes the section tree (depth pruning, continuity repair) applies typographic rules: orphan/widow prevention, keep-with-next heading policies, page-break strategies for tables and code blocks.
Layer 3: Typst Generator + Template Manager. Converts the composed IR into Typst source code. Templates handle page setup (paper size, margins, fonts, headers/footers) with multiple preset styles.
Layer 4: PDF Renderer. Compiles the Typst source into a PDF via the typst CLI. Caches results with TTL-based eviction. Supports per-page preview extraction from cached renders.
Quick Start
# Prerequisites: Python 3.11+, Typst CLI
# Install from source
git clone https://github.com/DCode1119/MarkdownPublishingMCP
cd MarkdownPublishingMCP
python -m venv .venv
pip install -r requirements.txt
# Run the server
python -m md_publishing_mcp
Usage
The server exposes two MCP tools:
| Tool | Description | Key Parameters |
|---|---|---|
render |
Convert Markdown to PDF | markdown, paper, margin(optional), template(optional) |
preview |
Retrieve a cached page preview | render_id, page |
Environment Variables
| Variable | Default | Description |
|---|---|---|
MCP_MAX_INPUT_SIZE |
10485760 (10 MB) |
Maximum input markdown size in bytes |
MCP_MAX_PAGES |
200 |
Maximum allowed pages per render |
MCP_CACHE_TTL |
600 |
Cache lifetime in seconds |
MCP_MAX_CACHED |
20 |
Maximum cached render results |
MCP_RENDER_TIMEOUT |
120.0 |
Typst compile timeout in seconds |
MCP_DEBUG |
false |
Enable debug logging |
Example: render a document
{
"markdown": "# Project Architecture\n\nThis document describes...",
"paper": "a4",
"margin": { "top": 20, "bottom": 20, "left": 25, "right": 25 }
}
Response:
{
"pdf": "<base64-encoded PDF bytes>",
"pages": 5,
"render_id": "r1712345678_1",
"warnings": []
}
Example: preview a page
{
"render_id": "r1712345678_1",
"page": 3
}
Response:
{
"page": 3,
"total_pages": 5,
"pdf": "<base64-encoded page PDF bytes>",
"warnings": []
}
Tech Stack
| Component | Technology |
|---|---|
| Language | Python 3.11+ |
| Framework | MCP SDK (official Python) |
| Markdown Parsing | markdown-it-py |
| Typesetting Engine | Typst (CLI) |
| Schema Validation | Pydantic v2 |
Project Status
All four layers are implemented and integrated. The pipeline has been verified end-to-end up to Typst source generation. PDF rendering requires the typst CLI binary to be installed and available on PATH.
Contributing
Contributions, ideas, and feedback are welcome. Open an issue or pull request on GitHub.
See Doc/ for detailed specifications and AGENTS.md for development workflow conventions.
License
MIT. See LICENSE for details.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file md_publishing_mcp-0.1.0.tar.gz.
File metadata
- Download URL: md_publishing_mcp-0.1.0.tar.gz
- Upload date:
- Size: 49.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
73699ab248db35790c827cef19b3c13d09986b37a98dd4fe76d6a5a425326bee
|
|
| MD5 |
9150174b37d7cb48da21ca4013e6c096
|
|
| BLAKE2b-256 |
737e59fa2ffba911513a0393f9c390c5ddf59d55dab60ad5832c0998d61c0736
|
Provenance
The following attestation bundles were made for md_publishing_mcp-0.1.0.tar.gz:
Publisher:
publish.yml on DCode1119/MarkdownPublishingMCP
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
md_publishing_mcp-0.1.0.tar.gz -
Subject digest:
73699ab248db35790c827cef19b3c13d09986b37a98dd4fe76d6a5a425326bee - Sigstore transparency entry: 1761913831
- Sigstore integration time:
-
Permalink:
DCode1119/MarkdownPublishingMCP@c49cfaf36bd3c0b0857647aa8e9eaf71c04296be -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/DCode1119
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@c49cfaf36bd3c0b0857647aa8e9eaf71c04296be -
Trigger Event:
release
-
Statement type:
File details
Details for the file md_publishing_mcp-0.1.0-py3-none-any.whl.
File metadata
- Download URL: md_publishing_mcp-0.1.0-py3-none-any.whl
- Upload date:
- Size: 37.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f35892051761d5e8ca802401e26a94deb7e7547e65d86af3c22a8b561d7fbbdf
|
|
| MD5 |
9da7eb79221a6b35f3a15015152b0eb0
|
|
| BLAKE2b-256 |
a54db0f0053b99dfb9c74bf7094838be225b22f256e80c4e6b430957e7576d90
|
Provenance
The following attestation bundles were made for md_publishing_mcp-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on DCode1119/MarkdownPublishingMCP
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
md_publishing_mcp-0.1.0-py3-none-any.whl -
Subject digest:
f35892051761d5e8ca802401e26a94deb7e7547e65d86af3c22a8b561d7fbbdf - Sigstore transparency entry: 1761914026
- Sigstore integration time:
-
Permalink:
DCode1119/MarkdownPublishingMCP@c49cfaf36bd3c0b0857647aa8e9eaf71c04296be -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/DCode1119
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@c49cfaf36bd3c0b0857647aa8e9eaf71c04296be -
Trigger Event:
release
-
Statement type: