How to Create PDFs from Markdown and Modify Existing PDFs Using Desktop Commander MCP
Desktop Commander MCP provides native PDF manipulation through parseMarkdownToPdf for markdown conversion and editPdf for page-level editing, enabling automated document generation and modification via Chrome-based rendering and pdf-lib operations.
Desktop Commander MCP, the open-source repository by wonderwhy-er, treats PDFs as first-class file types with dedicated tools for creating documents from markdown and performing surgical page-level modifications. This guide examines the actual source implementation in wonderwhy-er/DesktopCommanderMCP to show you how to generate PDFs programmatically and modify existing documents using the built-in MCP server capabilities.
Generating PDFs from Markdown
The parseMarkdownToPdf function in src/tools/pdf/markdown.ts (lines 87-103) handles the conversion of markdown strings to PDF buffers. This process relies on headless Chrome rendering through the md-to-pdf library.
Chrome Discovery and Rendering Pipeline
Before rendering occurs, the system ensures a Chrome executable is available via getChromePath. This function checks the private Puppeteer cache first, falls back to system-installed Chrome, and finally installs a fresh Chrome build via @puppeteer/browsers if needed. The discovered Chrome path is injected into launch_options so md-to-pdf can launch without searching the system.
The conversion accepts optional layout parameters including page size and margins, returning a buffer that can be written directly to disk or passed to other operations.
The parseMarkdownToPdf Implementation
import { parseMarkdownToPdf } from './src/tools/pdf/markdown.js';
const markdown = `
# Hello, Desktop Commander
This PDF is generated from **markdown** using the built‑in PDF tool.
`;
(async () => {
const pdfBuffer = await parseMarkdownToPdf(markdown);
// Write the buffer wherever you need it
await import('fs/promises').then(fs => fs.writeFile('hello.pdf', pdfBuffer));
})();
Modifying Existing PDFs
For page-level modifications, Desktop Commander MCP implements editPdf in src/tools/pdf/manipulations.ts (lines 95-131). This function uses pdf-lib to load documents, execute sequential operations, and return modified buffers.
The editPdf Workflow
The function loads the target PDF using PDFDocument.load, then processes an array of operations sequentially. Each operation is either a deletion or insertion, validated against Zod schemas before execution. After processing all operations, pdfDoc.save() produces a modified Uint8Array.
Delete and Insert Operations
Delete operations remove pages using pdfDoc.removePage after normalizing negative indices via normalizePageIndexes. Insert operations support two content sources: a markdown string (converted on-the-fly via parseMarkdownToPdf) or an existing PDF file. Pages are copied from the source document and inserted at the requested index.
import { editPdf } from './src/tools/pdf/manipulations.js';
// Example: Delete pages 3–5 from an existing PDF
(async () => {
const modified = await editPdf('source.pdf', [
{ type: 'delete', pageIndexes: [2, 3, 4] } // zero‑based indexes
]);
await import('fs/promises').then(fs => fs.writeFile('trimmed.pdf', modified));
})();
import { editPdf } from './src/tools/pdf/manipulations.js';
const markdownPage = `
## New Section
Added via markdown → PDF conversion.
`;
// Example: Insert a markdown-generated page after page 2
(async () => {
const result = await editPdf('source.pdf', [
{
type: 'insert',
pageIndex: 2, // after the second page (0‑based)
markdown: markdownPage
}
]);
await import('fs/promises').then(fs => fs.writeFile('updated.pdf', result));
})();
Unified File Handler Interface
The PdfFileHandler in src/utils/files/pdf.ts (lines 14-93) exposes a uniform read/write interface for PDFs within the generic file system. Read operations leverage parsePdfToMarkdown (implemented in src/tools/pdf/lib/pdf2md.ts) to extract text, images, and metadata using @opendocsg/pdf2md. Write operations dispatch to either parseMarkdownToPdf (when content is a string) or editPdf (when content is an array of operations).
Schema Validation
PDF editing operations are validated against strict Zod schemas defined in src/tools/schemas.ts. The PdfInsertOperationSchema (lines 84-90) validates insertion parameters including pageIndex and optional markdown content, while PdfDeleteOperationSchema (lines 92-95) validates the pageIndexes array for deletions.
When using the generic tool dispatcher, payloads are validated against WritePdfArgsSchema before processing:
{
"path": "report.pdf",
"content": [
{ "type": "delete", "pageIndexes": [0] },
{ "type": "insert", "pageIndex": 0, "markdown": "# Executive Summary" }
]
}
Summary
- Use
parseMarkdownToPdfinsrc/tools/pdf/markdown.tsto convert markdown strings to PDF buffers using Chrome/Chromium rendering via md-to-pdf. - Leverage
editPdfinsrc/tools/pdf/manipulations.tsto perform page-level deletions and insertions using pdf-lib operations. - The
PdfFileHandlerinsrc/utils/files/pdf.tsprovides a unified read/write interface that leveragespdf2mdfor parsing existing documents. - Operations are validated against Zod schemas defined in
src/tools/schemas.ts, ensuring type safety for both insert and delete commands.
Frequently Asked Questions
Does Desktop Commander MCP require Chrome to be installed?
No, Chrome is not strictly required at installation. The system uses getChromePath to locate a Chrome binary, checking first for a cached Puppeteer build, then system-installed Chrome, and finally downloading Chrome on-demand via @puppeteer/browsers if needed for the md-to-pdf rendering pipeline.
Can I insert pages from existing PDF files or only from markdown?
Both options are supported. When inserting pages via editPdf, you can provide a markdown property to generate new content on the fly, or supply an existing PDF path. The function copies page objects from the source document and inserts them at the specified index using pdf-lib's copy and insert methods.
How does page indexing work when deleting or inserting pages?
Desktop Commander MCP uses zero-based indexing throughout its PDF manipulation functions. The editPdf function normalizes negative indices via normalizePageIndexes before calling pdfDoc.removePage, ensuring consistent behavior whether you specify absolute positions or negative offsets from the end of the document.
What validation is performed on PDF operations before execution?
All PDF editing operations are validated against Zod schemas defined in src/tools/schemas.ts. Specifically, PdfInsertOperationSchema (lines 84-90) and PdfDeleteOperationSchema (lines 92-95) validate the shape of insert and delete operations, respectively, ensuring type safety before editPdf processes the operations array.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →