Media
pdf-creator - Claude MCP Skill
Creates professional PDF documents from markdown, HTML, DOCX, or structured content with automatic table of contents, smart pagination, headers, footers, bookmarks, and multi-page layouts
SEO Guide: Enhance your AI agent with the pdf-creator tool. This Model Context Protocol (MCP) server allows Claude Desktop and other LLMs to creates professional pdf documents from markdown, html, docx, or structured content with automatic t... Download and configure this skill to unlock new capabilities for your AI workflow.
Documentation
SKILL.md# PDF Creator Skill## PurposeCreate professional PDF documents from various input formats including markdown, HTML, DOCX, or structured content. Generate presentation-ready PDFs for sharing, archiving, and distribution. Primary use cases: markdown to PDF conversion, professional reports, final deliverables.## Core Capabilities1. Markdown to PDF Conversion - Full markdown syntax support - Preserves formatting and structure - Syntax-highlighted code blocks - Embedded images and tables - Custom styling via CSS2. HTML to PDF Conversion - Render HTML with full CSS support - Responsive layouts - Web fonts and custom typography - Complex layouts with flexbox/grid3. Multi-Source Input - Markdown files → PDF - HTML files → PDF - DOCX files → PDF via conversion - Plain text → PDF with formatting - JSON/structured data → formatted PDF4. PDF Manipulation - Merge multiple PDFs - Split PDFs by page range - Add/remove pages - Rotate pages - Extract text and images5. Professional Features - Headers and footers - Page numbers - Table of contents - Bookmarks/outline - Metadata author, title, subject - Watermarks - Password protection## Triggers- convert markdown to pdf- create a pdf- export to pdf- make a .pdf file- turn this into a pdf- generate pdf from [file]- merge these pdfs- split this pdf## Input Formats### Markdown Filebash/path/to/document.md### HTML ContenthtmlDOCTYPE htmlhtmlhead style body font-family: Arial /style/headbody h1Title/h1 pContent/p/body/html### Structured Contentjson title: Report Title, metadata: author: Author Name, subject: Report Subject , content: [ type: heading, text: Section 1, type: paragraph, text: Content... ]### Multiple Files for Mergingjson operation: merge, files: [file1.pdf, file2.pdf, file3.pdf], output: merged.pdf## Implementation Steps### 1. Parse Input- Identify input type and format- Read source files- Validate content### 2. Process Content#### For Markdownjavascriptconst marked = requiremarkedconst html = marked.parsemarkdownContent// Then convert HTML → PDF#### For HTMLjavascriptconst puppeteer = requirepuppeteerconst browser = await puppeteer.launchconst page = await browser.newPageawait page.setContenthtmlContentawait page.pdf path: output.pdf, format: A4 #### Alternative: PDFKit for programmatic generationjavascriptconst PDFDocument = requirepdfkitconst doc = new PDFDocumentdoc.pipefs.createWriteStreamoutput.pdfdoc.fontSize25.textTitle, 100, 100doc.end### 3. Apply Styling- Custom CSS for markdown/HTML conversions- Font selection system fonts or embedded- Color schemes- Margins and padding- Page layout settings### 4. Add Metadatajavascript title: Document Title, author: DollhouseMCP, subject: Generated PDF, keywords: markdown, pdf, conversion, creator: DollhouseMCP PDF Creator, producer: Puppeteer/PDFKit### 5. Save PDF- Write to file system- Set permissions- Verify PDF is not corrupted- Report file size and page count## DependenciesRequired packages:### Option 1: Puppeteer Recommended for markdown/HTMLjson puppeteer: ^21.0.0, marked: ^11.0.0### Option 2: PDFKit Programmatic PDF generationjson pdfkit: ^0.14.0, markdown-it: ^14.0.0### Option 3: PDF Manipulationjson pdf-lib: ^1.17.0, pdf-parse: ^1.1.1## Example Usage### Convert Markdown to PDFbashInput: Convert README.md to PDFSteps:1. Read README.md2. Parse markdown → HTML3. Apply professional styling4. Generate PDF with page numbers5. Save as README.pdf6. Report: Created README.pdf 3 pages, 245 KB### Create Professional ReportbashInput: Create a PDF report with title page and table of contentsSteps:1. Create title page with metadata2. Generate table of contents from headings3. Add content pages with proper formatting4. Include headers/footers with page numbers5. Add bookmarks for navigation6. Save as report-date.pdf### Merge Multiple PDFsbashInput: Merge chapter1.pdf, chapter2.pdf, and chapter3.pdfSteps:1. Load all source PDFs2. Verify PDF validity3. Combine in specified order4. Add continuous page numbering5. Save as merged-chapters.pdf### Split PDF by PagesbashInput: Split report.pdf into separate pagesSteps:1. Load report.pdf2. Count total pages3. Extract each page to separate PDF4. Save as report-page-01.pdf, report-page-02.pdf, etc.5. Report: Created 15 separate PDF files## Styling Options### CSS for Markdown/HTML Conversioncss@page size: A4 margin: 1in @top-center content: Document Title font-size: 10pt color: #666 @bottom-right content: Page counterpage font-size: 10pt body font-family: Georgia, serif font-size: 12pt line-height: 1.6 color: #333h1 font-size: 24pt color: #2c3e50 page-break-before: always margin-top: 0code background: #f4f4f4 padding: 2px 6px border-radius: 3px font-family: Courier New, monospacepre background: #f8f8f8 padding: 16px border-left: 4px solid #2c3e50 overflow-x: autotable border-collapse: collapse width: 100% margin: 16px 0th, td border: 1px solid #ddd padding: 8px 12px text-align: leftth background: #f2f2f2 font-weight: bold### Puppeteer PDF Optionsjavascriptawait page.pdf path: output.pdf, format: A4, // or Letter, Legal, etc. printBackground: true, // Include background colors/images margin: top: 1in, right: 1in, bottom: 1in, left: 1in , displayHeaderFooter: true, headerTemplate: div style=font-size:10pt text-align:center width:100%Header/div, footerTemplate: div style=font-size:10pt text-align:center width:100%span class=pageNumber/span / span class=totalPages/span/div, preferCSSPageSize: false## Error Handling### Common Errors1. File Not Found - Error: Source file doesnt exist - Solution: Verify path exists - Message: Source file not found: path2. Invalid PDF - Error: Corrupted source PDF for merge/split - Solution: Validate PDF before processing - Message: Invalid or corrupted PDF: filename3. Memory Limit - Error: Large file exceeds memory - Solution: Process in chunks or increase memory - Message: File too large: size. Try splitting the source first.4. Missing Dependencies - Error: Puppeteer/fonts not installed - Solution: Install required packages - Message: Missing dependency: package. Install with: npm install package5. Permission Denied - Error: Cannot write output file - Solution: Check directory permissions - Message: Cannot write to path. Check permissions.6. Browser Launch Failed Puppeteer - Error: Chrome/Chromium not found - Solution: Install browser or use bundled version - Message: Cannot launch browser. Run: npx puppeteer install chrome## Output Options### File Naming- Default: original-name.pdf- Custom: User-specified path- Auto: document-timestamp.pdf- Batch: basename-page-number.pdf### PDF Metadatajavascript Title: Document Title, Author: Author Name, Subject: Document Subject, Keywords: keyword1, keyword2, Creator: DollhouseMCP PDF Creator, Producer: Puppeteer/PDFKit, CreationDate: new Date, ModDate: new Date### Page Setup- Paper sizes: Letter, A4, Legal, Tabloid, A3, A5- Orientation: Portrait or Landscape- Margins: Customizable default 1 inch- Page numbers: Position and format- Headers/footers: Custom HTML templates## Best Practices1. Optimize File Size - Compress images before embedding - Use web fonts efficiently - Remove unused resources - Consider PDF/A for archival2. Accessibility - Tag PDF structure - Add alt text for images - Use proper heading hierarchy - Include document title - Maintain logical reading order3. Print Optimization - Use CMYK for print RGB for screen - Set proper bleed for printing - Embed fonts - Use appropriate resolution 300 DPI for print4. Security - Add password protection for sensitive docs - Set permissions printing, copying, editing - Remove metadata if privacy needed - Use encryption when appropriate5. Performance - Reuse browser instances Puppeteer - Process large batches sequentially - Cache rendered HTML - Use streams for large files## Advanced Features
### Automatic Table of Contents Generation
Generate a professional TOC from document headings with clickable links and accurate page numbers.
#### Step 1: Extract Headings from Markdown
```javascript
const marked = require('marked');
function extractHeadings(markdown) {
const headings = [];
const tokens = marked.lexer(markdown);
tokens.forEach((token, index) => {
if (token.type === 'heading') {
headings.push({
level: token.depth, // 1-6 for H1-H6
text: token.text, // Heading text
id: slugify(token.text), // For anchor links
index: index // Position in document
});
}
});
return headings;
}
function slugify(text) {
return text
.toLowerCase()
.replace(/[^\w\s-]/g, '')
.replace(/\s+/g, '-');
}
```
#### Step 2: Generate TOC HTML with Placeholders
```javascript
function generateTOC(headings) {
let tocHTML = `
<div class="table-of-contents">
<h1>Table of Contents</h1>
<nav class="toc-nav">
`;
headings.forEach((heading, i) => {
const indent = (heading.level - 1) * 20; // 20px per level
const pageClass = `toc-page-${i}`;
tocHTML += `
<div class="toc-entry level-${heading.level}" style="margin-left: ${indent}px;">
<a href="#${heading.id}" class="toc-link">
<span class="toc-title">${heading.text}</span>
<span class="toc-dots"></span>
<span class="toc-page ${pageClass}">00</span>
</a>
</div>
`;
});
tocHTML += `
</nav>
</div>
`;
return tocHTML;
}
```
#### Step 3: Add Anchor IDs to Headings
```javascript
function addAnchorIDs(html, headings) {
let modifiedHTML = html;
headings.forEach(heading => {
// Find H1-H6 tags and add id attribute
const regex = new RegExp(
`(<h${heading.level}[^>]*>)(${escapeRegex(heading.text)})(</h${heading.level}>)`,
'i'
);
modifiedHTML = modifiedHTML.replace(regex, (match, openTag, text, closeTag) => {
if (openTag.includes('id=')) return match; // Already has ID
return `${openTag.replace('>', ` id="${heading.id}">`)}}${text}${closeTag}`;
});
});
return modifiedHTML;
}
```
#### Step 4: Calculate Page Numbers with Puppeteer
```javascript
async function calculatePageNumbers(page, headings) {
const pageNumbers = await page.evaluate((headingIds) => {
const results = [];
headingIds.forEach(id => {
const element = document.getElementById(id);
if (!element) {
results.push(null);
return;
}
// Get element's position
const rect = element.getBoundingClientRect();
const scrollY = window.scrollY + rect.top;
// Calculate page number (assuming 11 inch pages at 96 DPI)
const pageHeight = 11 * 96; // Letter size height in pixels
const pageNum = Math.floor(scrollY / pageHeight) + 1;
results.push(pageNum);
});
return results;
}, headings.map(h => h.id));
return pageNumbers;
}
```
#### Step 5: Update TOC with Real Page Numbers
```javascript
async function updateTOCPageNumbers(page, headings, pageNumbers) {
await page.evaluate((pages) => {
pages.forEach((pageNum, index) => {
const pageElement = document.querySelector(`.toc-page-${index}`);
if (pageElement && pageNum !== null) {
pageElement.textContent = String(pageNum).padStart(2, '0');
}
});
}, pageNumbers);
}
```
#### Step 6: Complete TOC CSS Styling
```css
.table-of-contents {
page-break-after: always;
margin: 2em 0;
}
.table-of-contents h1 {
font-size: 28pt;
margin-bottom: 1em;
border-bottom: 2px solid #2c3e50;
padding-bottom: 0.5em;
}
.toc-nav {
font-size: 11pt;
}
.toc-entry {
margin: 0.5em 0;
page-break-inside: avoid;
}
.toc-link {
display: flex;
justify-content: space-between;
align-items: baseline;
text-decoration: none;
color: #2c3e50;
padding: 0.25em 0;
}
.toc-link:hover {
color: #3498db;
}
.toc-title {
flex-shrink: 0;
padding-right: 0.5em;
}
.toc-dots {
flex-grow: 1;
border-bottom: 1px dotted #999;
margin: 0 0.5em;
height: 0.8em;
}
.toc-page {
flex-shrink: 0;
font-weight: bold;
min-width: 2em;
text-align: right;
}
/* Indentation for different heading levels */
.level-1 .toc-title { font-weight: bold; font-size: 12pt; }
.level-2 .toc-title { font-size: 11pt; }
.level-3 .toc-title { font-size: 10pt; color: #555; }
.level-4 .toc-title { font-size: 9pt; color: #666; font-style: italic; }
```
#### Complete Implementation Example
```javascript
const puppeteer = require('puppeteer');
const marked = require('marked');
const fs = require('fs');
async function createPDFWithTOC(markdownPath, outputPath) {
// 1. Read markdown
const markdown = fs.readFileSync(markdownPath, 'utf8');
// 2. Extract headings
const headings = extractHeadings(markdown);
// 3. Convert markdown to HTML
let contentHTML = marked.parse(markdown);
// 4. Add anchor IDs to headings
contentHTML = addAnchorIDs(contentHTML, headings);
// 5. Generate TOC HTML
const tocHTML = generateTOC(headings);
// 6. Combine into full HTML document
const fullHTML = `
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
${cssStyles} /* Include all CSS from above */
</style>
</head>
<body>
${tocHTML}
<div class="content">
${contentHTML}
</div>
</body>
</html>
`;
// 7. Launch Puppeteer
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.setContent(fullHTML, { waitUntil: 'networkidle0' });
// 8. Calculate page numbers
const pageNumbers = await calculatePageNumbers(page, headings);
// 9. Update TOC with real page numbers
await updateTOCPageNumbers(page, headings, pageNumbers);
// 10. Generate PDF
await page.pdf({
path: outputPath,
format: 'Letter',
printBackground: true,
margin: { top: '1in', right: '1in', bottom: '1in', left: '1in' },
displayHeaderFooter: true,
footerTemplate: `
<div style="font-size: 9pt; text-align: center; width: 100%;">
<span class="pageNumber"></span> / <span class="totalPages"></span>
</div>
`
});
await browser.close();
console.log(`✓ PDF created with ${headings.length} TOC entries: ${outputPath}`);
}
// Usage
createPDFWithTOC('document.md', 'document.pdf');
```
### Smart Pagination
Prevent awkward page breaks with CSS page-break controls.
#### Avoid Breaking Inside Elements
```css
/* Never break inside these elements */
h1, h2, h3, h4, h5, h6 {
page-break-after: avoid;
page-break-inside: avoid;
}
pre, blockquote, table {
page-break-inside: avoid;
}
.toc-entry {
page-break-inside: avoid;
}
/* Keep headings with following content */
h1, h2, h3 {
page-break-after: avoid;
}
/* Always break before H1 (new chapter) */
h1 {
page-break-before: always;
}
/* Avoid orphans and widows */
p {
orphans: 3;
widows: 3;
}
```
#### Force Page Breaks
```css
/* Force break before major sections */
.chapter-start {
page-break-before: always;
}
/* Force break after TOC */
.table-of-contents {
page-break-after: always;
}
/* Prevent break after */
.keep-with-next {
page-break-after: avoid;
}
```
#### Page Break Strategy
```javascript
function addSmartPageBreaks(html) {
// Add page break before each H1 (except first)
html = html.replace(/(<h1[^>]*>)/g, (match, tag, offset) => {
if (offset === 0) return match;
return `<div style="page-break-before: always;"></div>${match}`;
});
// Keep headings with their first paragraph
html = html.replace(/(<\/h[1-3]>)\s*(<p>)/g, '$1<div class="keep-with-next">$2');
// Avoid breaking tables
html = html.replace(/(<table[^>]*>)/g, '<div style="page-break-inside: avoid;">$1');
html = html.replace(/(<\/table>)/g, '$1</div>');
return html;
}
```
### Bookmarks/Outline
Add PDF bookmarks for navigation (requires pdf-lib post-processing).
```javascript
const { PDFDocument } = require('pdf-lib');
async function addBookmarks(pdfPath, headings, pageNumbers) {
const existingPdfBytes = await fs.promises.readFile(pdfPath);
const pdfDoc = await PDFDocument.load(existingPdfBytes);
// Create outline/bookmarks
const outline = [];
headings.forEach((heading, i) => {
const pageIndex = (pageNumbers[i] || 1) - 1;
outline.push({
title: heading.text,
to: pdfDoc.getPage(pageIndex),
level: heading.level
});
});
// Note: pdf-lib doesn't directly support outlines yet
// Use alternative library or manual PDF manipulation
// This is a conceptual example
const pdfBytes = await pdfDoc.save();
await fs.promises.writeFile(pdfPath, pdfBytes);
}### Watermarksjavascript// Add watermark to each pagedoc.addWatermark text: DRAFT, opacity: 0.3, angle: 45, fontSize: 72, color: #cccccc### Forms and Fieldsjavascript// Create fillable PDF formsconst form = pdfDoc.getFormconst textField = form.createTextFieldfield.nametextField.setTextDefault value## Integration with TemplatesWorks with DollhouseMCP template elements:bash# Use template to create PDFInput: Create a report using the monthly-report templateFlow:1. Load monthly-report template2. Populate with data3. Render to markdown/HTML4. Convert to PDF with this skill5. Apply professional styling6. Save output## Performance Considerations- Puppeteer: Reuse browser instances, 100-200ms per page- PDFKit: Fast for programmatic generation, 10-50ms per page- Large files: Stream processing, consider memory limits- Batch processing: Queue system for multiple conversions- Images: Optimize/compress before embedding## Testing Checklist- [ ] Markdown → PDF basic conversion- [ ] HTML → PDF with CSS styling- [ ] Code blocks with syntax highlighting- [ ] Tables with complex layouts- [ ] Images local and remote URLs- [ ] Links internal anchors and external- [ ] Multi-page documents- [ ] Headers and footers- [ ] Page numbers- [ ] Table of contents generation- [ ] PDF merge 2+ files- [ ] PDF split by page range- [ ] Metadata embedding- [ ] Password protection- [ ] Large file handling 50+ pages- [ ] Different page sizes/orientations## Notes- PDF/A: Use for long-term archiving ISO 19005- PDF/X: Use fSignals
Information
- Repository
- mickdarling/dollhouse-portfolio
- Author
- mickdarling
- Last Sync
- 1/14/2026
- Repo Updated
- 10/25/2025
- Created
- 1/13/2026
Reviews (0)
No reviews yet. Be the first to review this skill!
Related Skills
upgrade-webkit
Upgrade Bun's Webkit fork to the latest upstream version of Webkit.
upgrade-nodejs
Upgrading Bun's Self-Reported Node.js Version
cursorrules
CrewAI Development Rules
Confidence Check
Pre-implementation confidence assessment (≥90% required). Use before starting any implementation to verify readiness with duplicate check, architecture compliance, official docs verification, OSS references, and root cause identification.
Related Guides
Python Django Best Practices: A Comprehensive Guide to the Claude Skill
Learn how to use the python django best practices Claude skill. Complete guide with installation instructions and examples.
Mastering Python Development with Claude: A Complete Guide to the Python Skill
Learn how to use the python Claude skill. Complete guide with installation instructions and examples.
Mastering VSCode Extension Development with Claude: A Complete Guide to the TypeScript Extension Dev Skill
Learn how to use the vscode extension dev typescript Claude skill. Complete guide with installation instructions and examples.