PDF Manipulation System in DesktopCommanderMCP: Text Extraction, Markdown Conversion, and Modification

DesktopCommanderMCP provides a complete PDF manipulation pipeline that extracts text to Markdown using pdf2md, creates PDFs from Markdown via md-to-pdf with Puppeteer caching, and edits documents using pdf-lib, all exposed through a secure Server RPC API.

DesktopCommanderMCP treats PDFs as first-class files, offering a unified system for reading, writing, and editing PDF documents through Markdown intermediates. The architecture isolates third-party libraries behind a consistent TypeScript API, enabling reliable document processing for AI-driven workflows.

PDF Text Extraction Pipeline

The system extracts PDF content using the pdf2md library, wrapped in src/tools/pdf/lib/pdf2md.ts. This module parses PDF binaries into a PdfParseResult object containing page-wise text, embedded images, and document metadata.

The parsePdfToMarkdown function in src/tools/pdf/markdown.ts consumes this result to generate structured Markdown documents. During conversion, the extractor captures critical metadata including author, title, total page count, and per-page content boundaries, enabling downstream tools to make context-aware decisions based on document structure.

// Extract a remote PDF to Markdown
import { parsePdfToMarkdown } from '@/tools/pdf/index.js';

const pdfUrl = 'https://example.com/report.pdf';
const result = await parsePdfToMarkdown(pdfUrl);
console.log(result.markdown);        // Markdown string
console.log(result.metadata.title); // PDF title

Creating PDFs from Markdown

PDF generation leverages the md-to-pdf package within src/tools/pdf/markdown.ts. The mdToPdf function (also exposed as parseMarkdownToPdf) renders Markdown strings into PDF buffers, accepting optional configuration objects for page size, margins, and formatting.

To optimize performance, the implementation caches the Chrome executable required for headless rendering. The getPuppeteerCacheDir and findPuppeteerChrome functions manage a private Puppeteer cache, preventing repeated downloads and significantly speeding up subsequent conversion calls.

// Create a new PDF from Markdown
import { parseMarkdownToPdf } from '@/tools/pdf/index.js';

const markdown = '# Quarterly Report\n\nData and charts...';

const pdfBuffer = await parseMarkdownToPdf(markdown, { 
  pdf_options: { format: 'A4' } 
});
await fs.writeFile('quarterly.pdf', pdfBuffer);

Editing and Modifying Existing PDFs

All mutating operations are delegated to pdf-lib through src/tools/pdf/manipulations.ts. The editing workflow follows a consistent pattern: load the target PDF into a PDFDocument via loadPdfDocumentFromBuffer, apply one or more operations, then serialize the result using pdfDoc.save.

Page-Level Operations

The system supports three primary mutation types:

  • deletePages: Removes specified pages by zero-based index
  • insertPages: Splices new content (from existing PDFs or Markdown) at specific positions
  • replacePages: Substitutes existing pages with alternative content

When inserting Markdown-derived content, the system first converts the Markdown to a PDF buffer using parseMarkdownToPdf, then integrates it into the target document before saving.

// Edit a PDF – delete pages 2-4 and insert a new page at index 1
import { editPdf } from '@/tools/pdf/index.js';

await editPdf({
  pdfPath: 'original.pdf',
  operations: [
    { type: 'delete', pageIndexes: [1, 2, 3] },
    {
      type: 'insert',
      pageIndex: 0,
      markdown: '## New Intro Page\n\nWelcome!',

      pdfOptions: { pdf_options: { format: 'A4' } },
    },
  ],
});

Server RPC API Interface

The PDF capabilities are exposed to clients through the Server RPC API defined in src/server.ts. Three primary commands handle document workflows:

  • read_pdf: Converts a PDF (local path or URL) to Markdown and returns metadata. Requires path or url parameter.
  • write_pdf: Renders supplied Markdown into a new PDF file. Requires path and content parameters, with optional options for PDF formatting.
  • edit_pdf: Applies page-level edits (delete, insert, replace) on an existing PDF. Requires path and an operations array describing the modifications.

Architecture and Implementation Details

File Handler Abstraction

PDF handling is encapsulated in the PdfFileHandler class located in src/utils/files/pdf.ts. This handler exposes standardized read, write, and edit methods. A factory pattern in src/utils/files/factory.ts lazily instantiates and returns a singleton PDF handler instance, ensuring consistent resource management across the codebase.

Robust Error Handling and Security

All PDF-lib operations are wrapped in try/catch blocks with explicit cleanup. Temporary resources invoke pdfDocument.cleanup or destroy methods when available, preventing memory leaks during batch processing.

Security measures include explicit forbidding of direct filesystem writes for PDF creation—requiring use of the write_pdf command—and validation via isPdfFile MIME-type checks. Path validation ensures only legitimate PDF files are processed, protecting against directory traversal attacks.

Summary

  • Text extraction uses pdf2md via src/tools/pdf/lib/pdf2md.ts to parse PDFs into structured Markdown with metadata.
  • PDF creation employs md-to-pdf in src/tools/pdf/markdown.ts with Chrome executable caching for performance.
  • Document editing relies on pdf-lib in src/tools/pdf/manipulations.ts supporting delete, insert, and replace operations.
  • The Server RPC API in src/server.ts exposes read_pdf, write_pdf, and edit_pdf commands with mandatory parameter validation.
  • Architecture uses the PdfFileHandler singleton pattern with comprehensive error handling and security checks.

Frequently Asked Questions

How does DesktopCommanderMCP extract text from PDF files?

DesktopCommanderMCP uses the @opendocsg/pdf2md library wrapped in src/tools/pdf/lib/pdf2md.ts to parse PDF binaries into a PdfParseResult containing page-wise text, images, and metadata. The parsePdfToMarkdown function in src/tools/pdf/markdown.ts then transforms this result into a structured Markdown document while preserving document metadata like author and title.

What dependencies are required for Markdown-to-PDF conversion?

The Markdown-to-PDF conversion requires the md-to-pdf package, which internally uses Puppeteer to control a headless Chromium instance. DesktopCommanderMCP mitigates the performance overhead by caching the Chrome executable using getPuppeteerCacheDir and findPuppeteerChrome functions, avoiding repeated downloads across conversion calls.

Can DesktopCommanderMCP modify existing PDFs without recreating them?

Yes, the system can edit existing PDFs through the editPdf function in src/tools/pdf/manipulations.ts using the pdf-lib library. It supports page deletion, insertion of new content (from Markdown or other PDFs), and page replacement. The workflow loads the document via loadPdfDocumentFromBuffer, applies operations, and saves using pdfDoc.save.

What security measures protect PDF operations in the server?

The server in src/server.ts enforces path validation and MIME-type verification through isPdfFile checks to ensure only legitimate PDFs are processed. Direct filesystem writes are forbidden; all PDF creation must use the write_pdf RPC command. Additionally, PDF-lib operations include try/catch blocks with explicit cleanup or destroy calls to prevent memory leaks and resource exhaustion.

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 →