使用说明
Typst D2 Integration
Render D2 diagrams in Typst documents with two tools:
Tools
1. typst-d2-prep (CLI Preprocessor)
- ✅ Zero filesystem clutter - No intermediate
.svgfiles created - ✅ Full D2 feature support - All layouts (ELK, TALA, dagre), themes, sketch mode
- ✅ Inline syntax - D2 code embedded directly in
.typfiles - ✅ Simple workflow - One command replaces
typst compile
2. typst-d2-mcp (MCP Server)
- 🤖 AI Assistant Integration - Works with Claude Desktop, Cline, OpenCode, and other MCP clients
- 📝 Encourages Visual Documentation - AI creates Typst documents with embedded D2 diagrams
- ✨ Focused tool surface:
compile_typst_with_d2to compile,put_fileto place sources when the client cannot write to the server's filesystem - 🌐 Runs locally or hosted - stdio for a desktop client, or an HTTP server with GitHub sign-in, per-user workspaces and quota (see Hosted mode)
- 🎯 Best for: Generating technical documentation, architecture docs, and illustrated guides
Quick Start
CLI Preprocessor (typst-d2-prep)
Installation
# Option 1: Homebrew (macOS/Linux)
brew install --cask stormlantern-dev/tap/typst-d2-prep
# Option 2: Download pre-built binary from GitHub Releases
# https://github.com/dlouwers/typst-d2-mcp/releases
# Option 3: Build from source
git clone https://github.com/dlouwers/typst-d2-mcp.git
cd typst-d2-mcp
go build -o typst-d2-prep ./cmd/typst-d2-prep
# Option 4: Install with go install
go install github.com/dlouwers/typst-d2-mcp/cmd/typst-d2-prep@latest
# Verify installation
typst-d2-prep version
# Verify D2 is installed
d2 --version
# If not: curl -fsSL https://d2lang.com/install.sh | sh -s --
Usage
Your Typst file (document.typ):
= Architecture Diagram
#d2[
client -> server -> database
]
#d2(layout: "elk", theme: "0")[
user: User {shape: person}
app: Application
user -> app: Uses
]
Compile:
typst-d2-prep compile document.typ
# ✅ Creates document.pdf with embedded diagrams
MCP Server (typst-d2-mcp)
The MCP server provides AI assistants with tools to render D2 diagrams and compile Typst documents.
Installation
# Option 1: Homebrew (macOS/Linux)
brew install --cask stormlantern-dev/tap/typst-d2-mcp
# Option 2: Download pre-built binary from GitHub Releases
# https://github.com/dlouwers/typst-d2-mcp/releases
# Option 3: Build from source
git clone https://github.com/dlouwers/typst-d2-mcp.git
cd typst-d2-mcp
go build -o typst-d2-mcp ./cmd/typst-d2-mcp
# Option 4: Install with go install
go install github.com/dlouwers/typst-d2-mcp/cmd/typst-d2-mcp@latest
Claude Desktop Configuration
Add to your Claude Desktop config file:
macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
Linux: ~/.config/Claude/claude_desktop_config.json
{
"mcpServers": {
"typst-d2": {
"command": "/opt/homebrew/bin/typst-d2-mcp"
}
}
}
Note: If installed via Homebrew, the binary is at /opt/homebrew/bin/typst-d2-mcp (macOS ARM), /usr/local/bin/typst-d2-mcp (macOS Intel) or /home/linuxbrew/.linuxbrew/bin/typst-d2-mcp (Linux); brew --prefix prints the first part. Adjust path if built from source.
The tap moved from dlouwers/tap to stormlantern-dev/tap. If you tapped the old name, it keeps working through GitHub's redirect; see HOMEBREW_SETUP.md to switch.
Upgrading from a version before 2.2: the tap now ships casks instead of formulae, and Homebrew does not move a third-party formula to a cask on its own. Switch once:
brew uninstall --formula typst-d2-prep typst-d2-mcp
brew install --cask stormlantern-dev/tap/typst-d2-prep stormlantern-dev/tap/typst-d2-mcp
Available Tools
compile_typst_with_d2 - Compile Typst documents with embedded D2 diagrams
The primary tool, and the one whose description steers AI assistants toward rich, visual documentation.
Input:
file_path(required): Typst source file (.typ) containing #d2[...] blocks. Absolute in local stdio mode; workspace-relative in hosted mode, where paths that escape the caller's workspace are rejected.
Output:
- A success message, plus a
resource_linkto the PDF (typst-d2://pdf/..., readable with the standard MCPresources/read). In hosted mode the result also carries a short-lived HTTPS download URL, for clients that render links but not resource links.
put_file - Write a file into the server's active workspace
Only needed when your client cannot write to the server's filesystem — that is, when talking to a hosted server over HTTP. Against a local stdio server, use your own editor or filesystem tools instead; there is no reason to push file contents through the MCP channel.
Input:
path(required): destination, workspace-relative in hosted modecontent(required),encoding(optional):utf8(default) orbase64
The tool's description guides AI assistants to:
- Use D2 diagrams for system architectures, flowcharts, ERDs, and technical illustrations
- Embed diagrams directly using #d2[...] syntax
- Support all D2 features (layouts, themes, sketch mode)
- Create clean documentation with no intermediate files
Example Usage
User: "Create documentation for a microservices architecture"
AI assistant:
1. Creates Typst document with headings and content
2. Embeds D2 diagrams using #d2[...] blocks:
- System architecture overview
- Service interaction diagrams
- Database schema (ERD)
3. Saves to .typ file
4. Calls compile_typst_with_d2 with file path
5. Returns PDF with embedded diagrams
User: "Document this API flow: client -> gateway -> auth -> service -> database"
AI assistant:
1. Creates Typst document explaining the API flow
2. Adds D2 diagram:
#d2(layout: "elk")[
client: Client {shape: person}
gateway: API Gateway
auth: Auth Service
service: Business Service
database: Database {shape: cylinder}
client -> gateway: HTTPS
gateway -> auth: Verify token
auth -> service: Authorized request
service -> database: Query
]
3. Saves and compiles
Result: Professional documentation with visual diagram
Hosted mode
The same binary runs as an HTTP server, which is how you would offer it to people who are not on your machine. Run your own — this repository does not point at a shared instance.
In this mode the server:
- serves the MCP Streamable HTTP transport at
/mcp(configurable viaTYPST_D2_MCP_PATH). That URL is the only thing a user needs: the server also acts as an OAuth 2.1 authorization server, so a client like Claude.ai discovers it from the401challenge, registers itself, and walks the user through GitHub sign-in — no token to copy and paste - gives each authenticated user a sandboxed workspace;
file_pathandput_filepaths are resolved inside it, and traversal is rejected - meters compiles with a per-day quota, with a per-user override
- mints short-lived download links for compiled PDFs, for clients that render HTTPS links but not MCP resource links
- offers an admin UI at
/adminfor the operator: invite users, set or remove a user's quota, revoke access and API keys, delete a user, and read an audit log of all of it - garbage-collects expired links and aged-out workspace files on a timer
Access is invite-only once you name an administrator, and an operator manages
who gets in from /admin.
See DEPLOYMENT.md for the full recipe: GitHub OAuth app setup, every environment variable, docker-compose and Kubernetes manifests, schema migrations, and hardening notes.
How It Works
- Parse - Scans your
.typfile for#d2[...]blocks - Extract - Pulls out D2 code and options from each block
- Render - For each diagram, calls
d2 - -(stdin→stdout streaming) - Encode - Converts SVG to base64
- Import - Adds
#import "@preview/based:0.2.0": decode64at the top - Replace - Substitutes
#d2[...]with#image(decode64("..."), format: "svg") - Compile - Runs
typst compileon the processed document - Cleanup - Deletes temporary
.typfile, keeps only your original + PDF
Result: Your PDF contains embedded SVGs, no leftover files, clean filesystem.
Requirements
- Go 1.26+ (for building from source, optional — see
go.modfor the exact directive) - D2 CLI installed and in PATH: https://d2lang.com/tour/install
- Typst 0.14.2+: https://github.com/typst/typst
- Typst
basedpackage: Automatically imported (no manual setup needed)
Syntax Reference
Basic Diagram
#d2[
x -> y -> z
]
With Options
#d2(layout: "elk", theme: "0", sketch: "true")[
direction: right
user: User {
shape: person
}
app: Application {
ui: Web Interface
api: REST API
}
user -> app.ui: Browse
]
Available Options
| Option | Values | Default | Description |
|---|---|---|---|
layout |
"elk", "tala", "dagre" |
"elk" |
Layout engine |
theme |
"0"-"200" |
default | Theme ID |
sketch |
"true", "false" |
"false" |
Hand-drawn style |
center |
"true", "false" |
"false" |
Center in viewbox |
scale |
number or "auto" |
"auto" |
Scale factor |
pad |
Typst length (e.g., "10pt") |
none |
Padding around diagram |
Examples
See example.typ for a complete demo with multiple diagrams, including:
- Simple connections
- Styled diagrams with ELK layout, themes, and sketch mode
- Complex architecture with multi-level containers
Compile it:
typst-d2-prep compile example.typ
Technical Details
Base64 Encoding with based Package
The preprocessor uses the based package to decode base64-encoded SVG data:
#import "@preview/based:0.2.0": decode64
#image(decode64("PD94bWwgdmVyc2lvbj0iMS4wIj..."), format: "svg")
This approach:
- ✅ Avoids escaping issues with raw SVG strings
- ✅ Works reliably with all SVG content
- ✅ Uses an official Typst package (no custom code)
- ✅ Handles binary data correctly
See IMPLEMENTATION.md for detailed technical documentation.
Comparison to Alternatives
| Feature | typst-d2 (this) | Manual workflow | WASM plugin |
|---|---|---|---|
| Setup | Install script + D2 | Install D2 | N/A (impossible) |
| Syntax | #d2[code] |
#image("out.svg") |
#d2[code] |
| Filesystem | ✅ Clean | ❌ SVG files everywhere | ✅ Clean |
| D2 Features | ✅ 100% | ✅ 100% | ❌ 0% |
| Build | typst-d2-prep compile |
d2 ... && typst compile |
typst compile |
Troubleshooting
"d2 command not found"
Install D2:
curl -fsSL https://d2lang.com/install.sh | sh -s --
"No D2 diagrams found"
Make sure you're using the #d2[...] syntax (not #import "lib.typ").
Development
Building from Source
git clone https://github.com/dlouwers/typst-d2-mcp.git
cd typst-d2-mcp
go build -o typst-d2-prep ./cmd/typst-d2-prep
Running Tests
go test ./...
Browser-level checks for the admin UI live in playwright/ and run in CI. They
cover what a Go test cannot reach — cookie SameSite behaviour, htmx swaps, and
that every action still works with JavaScript disabled:
cd playwright && bun install && bunx playwright install chromium
bunx playwright test
The suite starts the server itself; no running instance is needed.
Using Devcontainer
The project includes a devcontainer — a plain Debian base with everything added as devcontainer features, so each tool's version is a one-line change:
- Go 1.26 (via the Go feature;
go.modkeeps its own language-version directive) - D2 and Typst CLIs, pinned to the versions the production image ships
- golangci-lint, pinned to the version CI runs, plus gopls and govulncheck
- kubectl and sqlite3, for inspecting a running deployment
- Node and bun, for the Playwright suite
Open in VS Code with the Dev Containers extension for instant setup.
Limitations
- No watch mode yet - Currently only supports single compilation
- No incremental builds - Every compile re-renders all diagrams
Future Improvements
- [ ] Watch mode with smart caching
- [ ] Incremental rendering (only changed diagrams)
- [ ] Parallel diagram rendering
- [x] Native binary (no Python dependency) - COMPLETED
- [ ] Typst package integration
Contributing
Contributions welcome! Please open an issue or PR.
License
MIT License - see LICENSE for details.
Credits
- D2: https://github.com/terrastruct/d2
- Typst: https://github.com/typst/typst
- based package: https://github.com/EpicEricEE/typst-based
Related Documentation
- QUICKSTART.md - Quick start guide
- DEPLOYMENT.md - Running the hosted server: OAuth, quota, admin UI, garbage collection, Kubernetes
- MCP_GUIDE.md - Working with the MCP server
- HOMEBREW_SETUP.md - Homebrew tap maintenance
- IMPLEMENTATION.md - Technical implementation details