# How Desktop Commander MCP Generates PDFs with Chrome/Chromium and What Styling Is Supported

> Learn how Desktop Commander MCP generates PDFs using headless Chrome/Chromium via Puppeteer. Discover support for full CSS styling, syntax highlighting, and page breaks.

- Repository: [Eduard Ruzga/DesktopCommanderMCP](https://github.com/wonderwhy-er/DesktopCommanderMCP)
- Tags: how-to-guide
- Published: 2026-08-01

---

**Desktop Commander MCP creates PDFs by converting Markdown to HTML and rendering it through a headless Chrome or Chromium instance controlled by Puppeteer, supporting full CSS styling, syntax highlighting, and precise page-break controls.**

Desktop Commander MCP is a Model Context Protocol server that provides advanced file operations, including robust PDF generation capabilities. The repository leverages Puppeteer to launch a headless Chrome or Chromium browser from a local cache, converting Markdown content into professionally formatted PDF documents while preserving all preview styling.

## The Chrome/Chromium PDF Generation Pipeline

The PDF generation process follows a three-stage pipeline that bridges Markdown content to printed output through a controlled browser environment.

### Markdown to HTML Conversion

The process begins in [`src/tools/pdf/markdown.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/tools/pdf/markdown.ts), where the `parseMarkdownToPdf` function first transforms Markdown strings into HTML using the same rendering engine that powers the built-in preview. This ensures visual parity between the on-screen preview and the final PDF output. The HTML generation supports inline `<style>` tags and external CSS references, allowing custom fonts, colors, and layout rules to be embedded directly in the content.

### Browser Discovery and Launch

Before rendering, the system locates a suitable Chrome or Chromium binary using `findPuppeteerChrome(cacheDir)`, which scans the Puppeteer cache directory for the newest available build (as implemented in [`test/test-pdf-chrome-cache.js`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/test/test-pdf-chrome-cache.js) lines 66-71). To prevent cache bloat, outdated builds are automatically removed via `pruneOldPuppeteerChromeBuilds` (lines 73-84). Once identified, Puppeteer launches the browser headlessly using the specific `executablePath`, creating an isolated environment for PDF generation.

### Rendering and Buffer Output

With the browser running, the generated HTML is loaded into a new page using `page.setContent(html, { waitUntil: 'networkidle0' })`, ensuring all resources finish loading before printing. The `page.pdf(options)` method then renders the content to a PDF buffer, accepting native Chrome parameters such as `format`, `margin`, `landscape`, and `scale`. This buffer is returned directly to the caller, ready for file system storage or further processing.

## Supported Styling and CSS Features

Because the PDF mirrors the Markdown preview's HTML output, any CSS affecting the preview also styles the PDF. The following features are fully supported:

- **Typography and Layout**: Headings (`#` through `######`), paragraphs, lists (ordered and unordered), and blockquotes render with the preview's default stylesheet, including font sizes, weights, and spacing.

- **Code Blocks and Syntax Highlighting**: Fenced code blocks inherit the preview's syntax highlighting theme, preserving background colors, font families, and token coloring in the final PDF.

- **Tables and Images**: Tables render with borders, padding, and alignment rules from the CSS, while images embed at their natural resolution respecting `max-width` constraints.

- **Custom CSS Injection**: Users can include `<style>` blocks or `<link>` references to external stylesheets within the Markdown to override default styling, adjust colors, or modify margins.

- **Page-Level Controls**: Native Chrome PDF options control paper size (A4, Letter, etc.), orientation (portrait/landscape), margins, and scaling factors passed through the `options` parameter of `page.pdf()`.

- **Page Breaks**: CSS properties `page-break-before`, `page-break-after`, and `page-break-inside` are respected, allowing precise control over where content flows across pages.

## Key Implementation Files

The PDF system is distributed across three primary locations in the repository:

| File Path | Purpose | Key Functions |
|-----------|---------|---------------|
| [`src/tools/pdf/markdown.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/tools/pdf/markdown.ts) | Core conversion logic | `parseMarkdownToPdf`, `parsePdfToMarkdown`, `editPdf` |
| [`src/utils/files/pdf.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/files/pdf.ts) | File handler wrapper | `PdfFileHandler` class, imports `parseMarkdownToPdf` (lines 8-13, 84-87) |
| [`test/test-pdf-chrome-cache.js`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/test/test-pdf-chrome-cache.js) | Chrome discovery utilities | `findPuppeteerChrome`, `pruneOldPuppeteerChromeBuilds` |

## Code Examples

### Generate PDF from Markdown String

The following example demonstrates direct usage of the `parseMarkdownToPdf` function to convert Markdown content into a PDF file:

```typescript
import { parseMarkdownToPdf } from '../src/tools/pdf/markdown.js';
import fs from 'fs/promises';

async function generateReport() {
  const markdown = `

# Quarterly Report

This report demonstrates **PDF generation** with styling.

## Key Metrics

| Metric | Value |
|--------|-------|
| Revenue | $100K |
| Growth | 15% |

\`\`\`javascript
console.log('Data processed');
\`\`\`
`;

  // Convert to PDF using headless Chrome
  const pdfBuffer = await parseMarkdownToPdf(markdown, {
    format: 'A4',
    margin: { top: '1cm', bottom: '1cm', left: '1.5cm', right: '1.5cm' },
    printBackground: true
  });

  await fs.writeFile('quarterly-report.pdf', pdfBuffer);
}

generateReport();

```

### Using the File Handler API

For integration with the broader file system interface, use the `PdfFileHandler` class from [`src/utils/files/pdf.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/files/pdf.ts):

```typescript
import { PdfFileHandler } from '../src/utils/files/pdf.js';
import fs from 'fs/promises';

const handler = new PdfFileHandler();

// Writes Markdown directly to PDF
await handler.write('output.pdf', '# Document Title\n\nContent here');

```

### Edit Existing PDF with Operations

When passed an array of edit operations instead of a string, the handler invokes `editPdf` to modify existing documents:

```typescript
import { PdfFileHandler } from '../src/utils/files/pdf.js';

const handler = new PdfFileHandler();

const operations = [
  { op: 'insert', page: 2, markdown: 'New content for page 2' },
  { op: 'delete', page: 5 }
];

// Applies edits using Chrome rendering pipeline
await handler.write('modified-report.pdf', operations);

```

## Summary

- **Desktop Commander MCP** generates PDFs by rendering Markdown-derived HTML through a headless Chrome or Chromium instance controlled by Puppeteer, ensuring high-fidelity output that matches the preview styling.
- **Styling support** includes full CSS capabilities, syntax highlighting, tables, images, custom fonts, and page-break controls via standard CSS properties and Chrome-native PDF options.
- **Key files** involved are [`src/tools/pdf/markdown.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/tools/pdf/markdown.ts) for core logic, [`src/utils/files/pdf.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/files/pdf.ts) for the file handler interface, and [`test/test-pdf-chrome-cache.js`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/test/test-pdf-chrome-cache.js) for Chrome binary management.

## Frequently Asked Questions

### Does Desktop Commander MCP require a system installation of Chrome?

No. The system maintains its own **Puppeteer cache** of Chrome builds. The `findPuppeteerChrome` function automatically locates the newest cached binary, and `pruneOldPuppeteerChromeBuilds` removes outdated versions to manage disk space. This ensures PDF generation works regardless of whether Chrome is installed on the host system.

### What CSS properties control pagination in the generated PDFs?

Standard CSS page-break properties are fully supported. You can use `page-break-before: always` to force a new page before an element, `page-break-after: always` to break after, and `page-break-inside: avoid` to prevent table rows or code blocks from splitting across pages. These properties are processed by Chrome's native print engine during the `page.pdf()` call.

### Can I add custom headers and footers to every page?

Yes. The `page.pdf()` options object supports `headerTemplate` and `footerTemplate` parameters, which accept HTML strings styled with specific CSS classes. These templates render on every page and can include dynamic content like page numbers using Puppeteer's print margin variables. Pass these options through the `parseMarkdownToPdf` function's configuration object.

### How does the styling in the PDF compare to the Markdown preview?

The PDF uses the **identical HTML rendering pipeline** as the built-in Markdown preview. Any styles applied in the preview—including custom themes, syntax highlighting, and layout adjustments—are preserved in the PDF output. This is achieved by reusing the same HTML generator before passing the content to Chrome for printing.