Wraps PDFKit to generate PDFs through MCP tools. You get pdf-document for basic text and image layouts, pdf-layout for absolute positioning with Yoga flexbox containers, and pdf-resume for turning JSON Resume schemas into formatted CVs with customizable sections and two-column layouts. Field templates use LiquidJS for date formats and localization. Runs via stdio or HTTP with npx, no authentication needed. Useful when you need programmatic PDF generation without hitting external APIs, whether that's rendering reports from structured data or letting an LLM assemble resumes on the fly. The flexbox engine handles responsive layouts if you're building more complex document structures.
Docs: https://mcp-z.github.io/mcp-pdf PDF generation MCP server for documents, layouts, and image export.
MCP supports stdio and HTTP.
Stdio
{
"mcpServers": {
"pdf": {
"command": "npx",
"args": ["-y", "@mcp-z/mcp-pdf"]
}
}
}
HTTP
{
"mcpServers": {
"pdf": {
"type": "http",
"url": "http://localhost:9010/mcp",
"start": {
"command": "npx",
"args": ["-y", "@mcp-z/mcp-pdf", "--port=9010"]
}
}
}
}
start is an extension used by npx @mcp-z/cli up to launch HTTP servers for you.
No OAuth or API keys required.
# List tools
mcp-z inspect --servers pdf --tools
# Create a simple PDF
mcp-z call pdf pdf-document '{"content":["Hello from MCP"]}'
Generate professional resumes from JSON Resume format.
Parameters:
filename (string, optional) - Filename for the PDF (defaults to "resume.pdf")resume (object, required) - JSON Resume schemasections (object, optional) - Section ordering and field templateslayout (object, optional) - Spatial arrangement (single-column or two-column)styling (object, optional) - Typography and spacing optionsfont (string, optional) - Custom fontpageSize (string, optional) - Page size (default: "LETTER")backgroundColor (string, optional) - Page background colorResume schema sections:
basics - Name, contact, summary, locationwork - Work experience with highlightseducation - Degrees and institutionsprojects - Personal/professional projectsskills - Skills grouped by categoryawards, certificates, languages, volunteer, publications, interests, referencesControl which sections appear and in what order using sections.sections:
await client.callTool('pdf-resume', {
resume: { /* JSON Resume data */ },
sections: {
sections: [
{ source: 'basics', render: 'header' },
{ source: 'basics.summary', title: 'Summary' },
{ source: 'work', title: 'Experience' },
{ source: 'skills', title: 'Skills' },
{ source: 'education', title: 'Education' }
]
}
});
Section config properties:
source (string, required) - Path to data in resume schema (e.g., basics, work, meta.customField)render (string, optional) - Built-in renderer. Use header explicitly or to force a renderertitle (string, optional) - Section heading (omit for no title)template (string, optional) - LiquidJS template for custom renderingAvailable renderers:
header - Name + contact line from basics (never auto-inferred)entry-list - Arrays with position/institution/organizationkeyword-list - Arrays with keywordslanguage-list - Arrays with languagecredential-list - Arrays with awarder/issuer/publisherreference-list - Arrays with referencetext - String or string arrayExample: custom section order with meta fields
await client.callTool('pdf-resume', {
resume: {
basics: { name: 'Jane Doe', email: 'jane@example.com' },
work: [{ /* ... */ }],
meta: { valueProp: 'Full-stack engineer with 10+ years experience...' }
},
sections: {
sections: [
{ source: 'basics', render: 'header' },
{ source: 'meta.valueProp', title: 'Value Proposition' },
{ source: 'work', title: 'Experience' }
]
}
});
Field templates use LiquidJS syntax to customize how fields are rendered.
Available field templates:
location - {{ city }}{% if region %}, {{ region }}{% endif %}dateRange - {{ start | date: 'MMM YYYY' }} - {{ end | date: 'MMM YYYY' | default: 'Present' }}degree - {{ studyType }}{% if area %}, {{ area }}{% endif %}credential - {{ title | default: name }}{% if awarder %}, {{ awarder }}{% endif %}language - {{ language }}{% if fluency %} ({{ fluency }}){% endif %}skill - {{ name }}: {{ keywords | join: ', ' }}contactLine - {{ items | join: ' | ' }}Date format tokens:
YYYY, YY, MMMM, MMM, MM, M, DD, DAvailable filters:
date - Format a date stringdefault - Fallback for empty valuestenure - Calculate durationjoin - Join array elementsExample: French resume
await client.callTool('pdf-resume', {
filename: 'cv-francais.pdf',
resume: { /* JSON Resume data */ },
sections: {
fieldTemplates: {
dateRange: "{{ start | date: 'MM/YYYY' }} - {{ end | date: 'MM/YYYY' | default: 'Present' }}",
location: '{{ city }}'
}
}
});
Example: verbose date format
await client.callTool('pdf-resume', {
filename: 'resume.pdf',
resume: { /* JSON Resume data */ },
sections: {
fieldTemplates: {
dateRange: "{{ start | date: 'MMMM YYYY' }} to {{ end | date: 'MMMM YYYY' | default: 'Present' }}"
}
}
});
await client.callTool('pdf-resume', {
filename: 'two-column-resume.pdf',
resume: {
basics: {
name: 'Jane Doe',
label: 'Product Designer',
email: 'jane@example.com'
},
work: [{
name: 'Design Studio',
position: 'Lead Designer',
startDate: '2019-03',
highlights: ['Redesigned product UI', 'Increased conversion by 25%']
}],
skills: [
{ name: 'Design', keywords: ['Figma', 'Sketch', 'Adobe XD'] },
{ name: 'Frontend', keywords: ['HTML', 'CSS', 'React'] }
],
languages: [
{ language: 'English', fluency: 'Native' },
{ language: 'Spanish', fluency: 'Intermediate' }
]
},
layout: {
style: 'two-column',
gap: 30,
columns: {
left: { width: '30%', sections: ['skills', 'languages'] },
right: { width: '70%', sections: ['work'] }
}
}
});
Layout options:
style - "single-column" (default) or "two-column"gap - Space between columns in points (default: 30)columns.left.width - Left column width (percentage or points)columns.left.sections - Section source paths for left columncolumns.right.width - Right column widthcolumns.right.sections - Section source paths for right columnCreate a PDF with precise positioning and Yoga flexbox layout.
Parameters:
filename (string, optional) - Filename for the PDF (defaults to "document.pdf")title (string, optional) - Document metadataauthor (string, optional) - Document metadatapageSetup (object, optional) - Page configurationcontent (array, required) - Content itemslayout (object, optional) - Layout optionsPage setup:
pageSetup: {
size: [612, 792],
margins: { top: 72, bottom: 72, left: 72, right: 72 },
backgroundColor: '#FFFFFF'
}
Content types:
Text and headings:
{
type: 'text',
text: 'Content here',
fontSize: 12,
bold: true,
color: '#000000',
align: 'left',
x: 100,
y: 200,
oblique: 15,
characterSpacing: 1,
moveDown: 1,
underline: true,
strike: true
}
Shapes:
{ type: 'rect', x: 50, y: 50, width: 200, height: 100, fillColor: '#FF0000', strokeColor: '#000000', lineWidth: 2 }
{ type: 'circle', x: 300, y: 400, radius: 50, fillColor: '#00FF00', strokeColor: '#000000', lineWidth: 1 }
{ type: 'line', x1: 100, y1: 100, x2: 500, y2: 100, strokeColor: '#0000FF', lineWidth: 2 }
Images and pages:
{ type: 'image', imagePath: '/path/to/image.png', width: 200, height: 150, x: 100, y: 200 }
{ type: 'pageBreak' }
Use type: 'group' to create flexbox containers:
{
type: 'group',
direction: 'row',
gap: 20,
flex: 1,
justify: 'center',
alignItems: 'center',
align: 'center',
width: 300,
height: 200,
padding: 15,
background: '#f5f5f5',
border: { color: '#333', width: 1 },
children: [
{ type: 'text', text: 'Child 1' },
{ type: 'text', text: 'Child 2' }
]
}
Common layout patterns:
Two equal columns:
{
type: 'group',
direction: 'row',
gap: 20,
children: [
{ type: 'group', flex: 1, children: [{ type: 'text', text: 'Left' }] },
{ type: 'group', flex: 1, children: [{ type: 'text', text: 'Right' }] }
]
}
Three columns with proportions (1:2:1):
{
type: 'group',
direction: 'row',
gap: 15,
children: [
{ type: 'group', flex: 1, children: [/* ... */] },
{ type: 'group', flex: 2, children: [/* ... */] },
{ type: 'group', flex: 1, children: [/* ... */] }
]
}
Centered card:
{
type: 'group',
width: 300,
align: 'center',
border: { color: '#333', width: 2 },
padding: 20,
children: [
{ type: 'heading', text: 'Card Title', align: 'center' },
{ type: 'text', text: 'Card content here' }
]
}
Space between items:
{
type: 'group',
direction: 'row',
justify: 'space-between',
children: [
{ type: 'text', text: 'Left' },
{ type: 'text', text: 'Right' }
]
}
Mixed positioning:
await client.callTool('pdf-layout', {
layout: { overflow: 'auto' },
content: [
{ type: 'heading', text: 'TITLE', x: 54, y: 50 },
{
type: 'group',
direction: 'row',
gap: 20,
x: 54,
y: 100,
children: [
{ type: 'group', flex: 1, children: [/* ... */] },
{ type: 'group', flex: 1, children: [/* ... */] }
]
},
{ type: 'text', text: 'Footer', x: 54, y: 700 }
]
});
Complete flyer example:
await client.callTool('pdf-layout', {
pageSetup: { backgroundColor: '#fffef5' },
content: [
{ type: 'heading', text: 'SUMMER FESTIVAL 2024', align: 'center', fontSize: 28, y: 50 },
{ type: 'text', text: 'July 15-17 | Central Park', align: 'center', y: 90 },
{
type: 'group',
direction: 'row',
gap: 20,
x: 54,
y: 130,
children: [
{
type: 'group',
flex: 1,
border: { color: '#2196f3', width: 2 },
padding: 15,
children: [
{ type: 'heading', text: 'MUSIC', align: 'center', fontSize: 18 },
{ type: 'text', text: 'Live bands all weekend' },
{ type: 'text', text: '- Main Stage' },
{ type: 'text', text: '- Acoustic Tent' }
]
},
{
type: 'group',
flex: 1,
border: { color: '#4caf50', width: 2 },
padding: 15,
children: [
{ type: 'heading', text: 'FOOD', align: 'center', fontSize: 18 },
{ type: 'text', text: '50+ local vendors' },
{ type: 'text', text: '- Food Court' },
{ type: 'text', text: '- Craft Beers' }
]
}
]
},
{
type: 'group',
width: 300,
align: 'center',
y: 400,
border: { color: '#ff9800', width: 2 },
padding: 15,
background: '#fff8e1',
children: [
{ type: 'heading', text: 'TICKETS', align: 'center', fontSize: 16 },
{ type: 'text', text: 'Early Bird: $25', align: 'center' },
{ type: 'text', text: 'At Door: $35', align: 'center' }
]
}
]
});
Color emoji render as inline images. Unicode text is supported across major scripts.
{
"basics": {
"name": "John Doe",
"summary": "Developer passionate about clean code"
}
}
Create a flowing PDF document with automatic pagination.
Render PDF pages to PNG images for previews or export.
Measure text width and height before layout.
None.
csoai-org/pdf-document-mcp
xt765/mcp-document-converter
io.github.xjtlumedia/markdown-formatter
io.github.ai-aviate/better-notion
suekou/mcp-notion-server
meterlong/mcp-doc