write_pdf
Create new PDF files from markdown content or modify existing PDFs by inserting or deleting pages using Desktop Commander MCP's file management capabilities.
Instructions
Create a new PDF file or modify an existing one.
THIS IS THE ONLY TOOL FOR CREATING AND MODIFYING PDF FILES.
RULES ABOUT FILENAMES:
- When creating a new PDF, 'outputPath' MUST be provided and MUST use a new unique filename (e.g., "result_01.pdf", "analysis_2025_01.pdf", etc.).
MODES:
1. CREATE NEW PDF:
- Pass a markdown string as 'content'.
write_pdf(path="doc.pdf", content="# Title\n\nBody text...")
2. MODIFY EXISTING PDF:
- Pass array of operations as 'content'.
- NEVER overwrite the original file.
- ALWAYS provide a new filename in 'outputPath'.
- After modifying, show original file path and new file path to user.
write_pdf(path="doc.pdf", content=[
{ type: "delete", pageIndexes: [0, 2] },
{ type: "insert", pageIndex: 1, markdown: "# New Page" }
])
OPERATIONS:
- delete: Remove pages by 0-based index.
{ type: "delete", pageIndexes: [0, 1, 5] }
- insert: Add pages at a specific 0-based index.
{ type: "insert", pageIndex: 0, markdown: "..." }
{ type: "insert", pageIndex: 5, sourcePdfPath: "/path/to/source.pdf" }
PAGE BREAKS:
To force a page break, use this HTML element:
<div style="page-break-before: always;"></div>
Example:
"# Page 1\n\n<div style=\"page-break-before: always;\"></div>\n\n# Page 2"
ADVANCED STYLING:
HTML/CSS and inline SVG are supported for:
- Text styling: colors, sizes, alignment, highlights
- Boxes: borders, backgrounds, padding, rounded corners
- SVG graphics: charts, diagrams, icons, shapes
- Images: <img src="/absolute/path/image.jpg" width="300" /> or 
Supports standard markdown features including headers, lists, code blocks, tables, and basic formatting.
Only works within allowed directories.
IMPORTANT: Always use absolute paths for reliability. Paths are automatically normalized regardless of slash direction. Relative paths may fail as they depend on the current working directory. Tilde paths (~/...) might not work in all contexts. Unless the user explicitly asks for relative paths, use absolute paths.
This command can be referenced as "DC: ..." or "use Desktop Commander to ..." in your instructions.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes | ||
| content | Yes | ||
| outputPath | No | ||
| options | No |
Implementation Reference
- MCP handler function for 'write_pdf' tool that validates input using WritePdfArgsSchema and delegates to the writePdf utility function.export async function handleWritePdf(args: unknown): Promise<ServerResult> { try { const parsed = WritePdfArgsSchema.parse(args); await writePdf(parsed.path, parsed.content, parsed.outputPath, parsed.options); const targetPath = parsed.outputPath || parsed.path; return { content: [{ type: "text", text: `Successfully wrote PDF to ${targetPath}${parsed.outputPath ? `\nOriginal file: ${parsed.path}` : ''}` }], }; } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); return createErrorResponse(errorMessage); } }
- src/tools/schemas.ts:83-104 (schema)Zod schema for validating arguments to the write_pdf tool, supporting both markdown string and PDF operations array.export const WritePdfArgsSchema = z.object({ path: z.string(), // Preprocess content to handle JSON strings that should be parsed as arrays content: z.preprocess( (val) => { // If it's a string that looks like JSON array, parse it if (typeof val === 'string' && val.trim().startsWith('[')) { try { return JSON.parse(val); } catch { // If parsing fails, return as-is (might be markdown content) return val; } } // Otherwise return as-is return val; }, z.union([z.string(), z.array(PdfOperationSchema)]) ), outputPath: z.string().optional(), options: z.object({}).passthrough().optional(), // Allow passing options to md-to-pdf });
- src/tools/filesystem.ts:838-892 (helper)Core utility function implementing PDF creation from markdown or editing existing PDFs using operations like insert/delete pages.export async function writePdf( filePath: string, content: string | PdfOperations[], outputPath?: string, options: any = {} ): Promise<void> { const validPath = await validatePath(filePath); const fileExtension = getFileExtension(validPath); if (typeof content === 'string') { // --- PDF CREATION MODE --- capture('server_write_pdf', { fileExtension: fileExtension, contentLength: content.length, mode: 'create' }); const pdfBuffer = await parseMarkdownToPdf(content, options); // Use outputPath if provided, otherwise overwrite input file const targetPath = outputPath ? await validatePath(outputPath) : validPath; await fs.writeFile(targetPath, pdfBuffer); } else if (Array.isArray(content)) { // Use outputPath if provided, otherwise overwrite input file const targetPath = outputPath ? await validatePath(outputPath) : validPath; const operations: PdfOperations[] = []; // Validate paths in operations for (const o of content) { if (o.type === 'insert') { if (o.sourcePdfPath) { o.sourcePdfPath = await validatePath(o.sourcePdfPath); } } operations.push(o); } capture('server_write_pdf', { fileExtension: fileExtension, operationCount: operations.length, mode: 'modify', deleteCount: operations.filter(op => op.type === 'delete').length, insertCount: operations.filter(op => op.type === 'insert').length }); // Perform the PDF editing const modifiedPdfBuffer = await editPdf(validPath, operations); // Write the modified PDF to the output path await fs.writeFile(targetPath, modifiedPdfBuffer); } else { throw new Error('Invalid content type for writePdf. Expected string (markdown) or array of operations.'); } }