How the `write_pdf` Tool Renders HTML, CSS & SVG for PDF Generation in DesktopCommanderMCP

The write_pdf tool supports HTML, CSS, and SVG by converting Markdown to HTML, then rendering that HTML through a headless Chromium browser before exporting to PDF.

The write_pdf tool in the DesktopCommanderMCP repository enables rich PDF generation by leveraging a full browser engine. When you pass content containing raw HTML, embedded styles, or inline SVG, the tool preserves these elements throughout the conversion pipeline rather than stripping or sanitizing them. This browser-based approach ensures that complex layouts and vector graphics render exactly as designed.

How HTML/CSS/SVG Support Works Under the Hood

The PDF generation pipeline in src/tools/pdf/markdown.ts follows a three-stage process that treats your content like a web page:

Markdown-to-HTML Conversion with markdown-it

First, the parseMarkdownToPdf function passes your content to md-to-pdf, which uses markdown-it to convert Markdown to HTML. Crucially, markdown-it does not escape or remove raw HTML blocks during this conversion.

This means any embedded HTML—<div> containers, <span> elements, or <style> tags—pass through unchanged to the next stage.

Headless Chromium Rendering via Puppeteer

The generated HTML is then opened in a Chrome/Chromium instance launched via Puppeteer. The getChromePath() utility in src/tools/pdf/markdown.ts handles Chrome detection and installation if needed.

Because this is a real browser engine, it:

  • Parses and applies CSS rules from <style> tags or external stylesheets
  • Renders SVG graphics at full vector quality
  • Executes any standard web layout algorithms (flexbox, grid, etc.)

PDF Export Through Chrome's Print Pipeline

Finally, Chromium's built-in PDF printer exports the rendered page to a buffer using mdToPdf({ content: markdown }, options). The result is a PDF that visually matches what you'd see in a desktop browser.

What HTML/CSS/SVG Features Are Supported

Because write_pdf delegates rendering to Chromium, you gain comprehensive web standards support:

Feature How to Use It Example
Raw HTML blocks Insert directly in Markdown <div class="callout">Note</div>
Embedded CSS <style> tag or inline style= <style>.red{color:red}</style>
Inline SVG <svg> element with markup <svg><circle cx="50" cy="50" r="40"/></svg>
External stylesheets Via md-to-pdf options styles: ['path/to/custom.css']

Practical Code Examples

Basic Markdown to PDF

await writePdf(
  "report.pdf",
  "# Quarterly Report\n\nRevenue increased 23% year-over-year."

);

PDF with Custom CSS Styling

const markdown = `
<style>
  .metric { font-size: 24px; font-weight: bold; color: #2ecc71; }
  .label { color: #7f8c8d; text-transform: uppercase; }
</style>

# Dashboard

<div class="metric">$1.2M</div>
<div class="label">Total Revenue</div>

Standard Markdown still works **normally**.
`;

await writePdf("styled-dashboard.pdf", markdown);

PDF with Inline SVG Graphics

const markdown = `

# Architecture Diagram

<svg width="400" height="200" viewBox="0 0 400 200">
  <rect x="20" y="50" width="100" height="80" fill="#3498db" rx="5"/>
  <rect x="160" y="50" width="100" height="80" fill="#e74c3c" rx="5"/>
  <rect x="300" y="50" width="80" height="80" fill="#2ecc71" rx="5"/>
  <path d="M120 90 L160 90" stroke="#34495e" stroke-width="2" marker-end="url(#arrow)"/>
  <path d="M260 90 L300 90" stroke="#34495e" stroke-width="2" marker-end="url(#arrow)"/>
  <defs>
    <marker id="arrow" markerWidth="10" markerHeight="10" refX="9" refY="3" orient="auto">
      <path d="M0,0 L0,6 L9,3 z" fill="#34495e"/>
    </marker>
  </defs>
  <text x="70" y="95" text-anchor="middle" fill="white" font-size="14">API</text>
  <text x="210" y="95" text-anchor="middle" fill="white" font-size="14">Cache</text>
  <text x="340" y="95" text-anchor="middle" fill="white" font-size="14">DB</text>
</svg>
`;

await writePdf("architecture.pdf", markdown);

Advanced Configuration with Chromium Options

await writePdf(
  "enterprise-report.pdf",
  "# Confidential\n\nQuarterly financial data.",

  undefined,
  {
    launch_options: {
      args: ["--no-sandbox", "--disable-setuid-sandbox"],
      executablePath: "/usr/bin/google-chrome"
    },
    pdf_options: {
      format: "A4",
      printBackground: true,
      margin: { top: "2cm", right: "2cm", bottom: "2cm", left: "2cm" },
      displayHeaderFooter: true,
      headerTemplate: '<div style="font-size:9px; color:#999; width:100%; text-align:center;">Company Name</div>',
      footerTemplate: '<div style="font-size:9px; color:#999; width:100%; text-align:center;"><span class="pageNumber"></span> / <span class="totalPages"></span></div>'
    },
    basedir: "/app/templates",
    styles: ["/app/templates/corporate.css"],
    as_html: false
  }
);

Key Source Files and Their Roles

  • src/tools/filesystem.ts — Contains the writePdf implementation that validates arguments and orchestrates PDF creation
  • src/tools/pdf/markdown.ts — Houses parseMarkdownToPdf and getChromePath() for Chromium management and md-to-pdf invocation
  • src/tools/schemas.ts — Defines WritePdfArgsSchema with flexible options typing that forwards to md-to-pdf
  • src/server.ts — Registers the write_pdf tool and exposes help documentation
  • package.json — Declares md-to-pdf and @puppeteer/browsers dependencies that enable the HTML/CSS/SVG pipeline

Summary

  • write_pdf supports HTML, CSS, and SVG by rendering content through a headless Chromium browser rather than using a limited markup converter.
  • The three-stage pipeline (Markdown → HTML → Chromium → PDF) preserves all web-standard formatting and graphics.
  • Raw HTML blocks, embedded <style> tags, and inline SVG elements pass through unchanged to the browser renderer.
  • Configure Chromium launch options and PDF export settings through the fourth options parameter forwarded to md-to-pdf.

Frequently Asked Questions

Can I use external CSS files instead of inline styles?

Yes. Pass file paths via the styles array in the options parameter. Files are resolved relative to the basedir option or absolute paths. The styles are injected into the HTML before Chromium rendering begins.

Does SVG support include complex features like gradients and filters?

All standard SVG 1.1 features supported by Chromium work correctly, including linear/radial gradients, filters, patterns, and animations (rendered as static frames). Since rendering uses the same engine as Google Chrome, you can verify compatibility by testing your SVG in a regular browser first.

What happens if Chrome isn't installed on the system?

The getChromePath() function in src/tools/pdf/markdown.ts automatically attempts to install a compatible Chromium build via @puppeteer/browsers if no system Chrome is detected. You can also specify a custom executable path through launch_options.executablePath.

Are there security concerns with rendering arbitrary HTML?

Because content executes in a headless browser, you should sanitize untrusted input before passing it to write_pdf. The tool does not implement its own CSP or sandboxing beyond what Puppeteer provides. For untrusted content, consider running the MCP server with restricted network access or pre-processing Markdown to strip dangerous HTML elements.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →