Skip to main content
Glama

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 ![alt](/path/image.jpg) 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
NameRequiredDescriptionDefault
pathYes
contentYes
outputPathNo
optionsNo

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); } }
  • 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 });
  • 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.'); } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/wonderwhy-er/ClaudeComputerCommander'

If you have feedback or need assistance with the MCP directory API, please join our Discord server