@mcp-z/mcp-pdf

Create PDFs without leaving your workflow. Perfect for documentation, reports, and creative projects. Productive PDF generation with full Unicode and emoji support.

@mcp-z/mcp-pdf

Docs: https://mcp-z.github.io/mcp-pdf PDF generation MCP server for documents, layouts, and image export.

Common uses

  • Generate PDFs from text or layouts
  • Render PDF pages as images
  • Measure text before layout

Transports

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.

Authentication

No OAuth or API keys required.

How to use

# List tools
mcp-z inspect --servers pdf --tools

# Create a simple PDF
mcp-z call pdf pdf-document '{"content":["Hello from MCP"]}'

Available tools

pdf-resume

Generate professional resumes from JSON Resume format.

Parameters:

  • filename (string, optional) - Filename for the PDF (defaults to "resume.pdf")
  • resume (object, required) - JSON Resume schema
  • sections (object, optional) - Section ordering and field templates
  • layout (object, optional) - Spatial arrangement (single-column or two-column)
  • styling (object, optional) - Typography and spacing options
  • font (string, optional) - Custom font
  • pageSize (string, optional) - Page size (default: "LETTER")
  • backgroundColor (string, optional) - Page background color

Resume schema sections:

  • basics - Name, contact, summary, location
  • work - Work experience with highlights
  • education - Degrees and institutions
  • projects - Personal/professional projects
  • skills - Skills grouped by category
  • awards, certificates, languages, volunteer, publications, interests, references

Section configuration

Control 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 renderer
  • title (string, optional) - Section heading (omit for no title)
  • template (string, optional) - LiquidJS template for custom rendering

Available renderers:

  • header - Name + contact line from basics (never auto-inferred)
  • entry-list - Arrays with position/institution/organization
  • keyword-list - Arrays with keywords
  • language-list - Arrays with language
  • credential-list - Arrays with awarder/issuer/publisher
  • reference-list - Arrays with reference
  • text - String or string array

Example: custom section order with meta fields

await client.callTool('pdf-resume', {
  resume: {
    basics: { name: 'Jane Doe', email: '[email protected]' },
    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

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, D

Available filters:

  • date - Format a date string
  • default - Fallback for empty values
  • tenure - Calculate duration
  • join - Join array elements

Example: 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' }}"
    }
  }
});

Two-column resume layout

await client.callTool('pdf-resume', {
  filename: 'two-column-resume.pdf',
  resume: {
    basics: {
      name: 'Jane Doe',
      label: 'Product Designer',
      email: '[email protected]'
    },
    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 column
  • columns.right.width - Right column width
  • columns.right.sections - Section source paths for right column

pdf-layout

Create 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 metadata
  • author (string, optional) - Document metadata
  • pageSetup (object, optional) - Page configuration
  • content (array, required) - Content items
  • layout (object, optional) - Layout options

Page 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' }

Flexbox layout engine

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

Emoji and Unicode support

Color emoji render as inline images. Unicode text is supported across major scripts.

{
  "basics": {
    "name": "John Doe",
    "summary": "Developer passionate about clean code"
  }
}

pdf-document

Create a flowing PDF document with automatic pagination.

pdf-image

Render PDF pages to PNG images for previews or export.

text-measure

Measure text width and height before layout.

Tools

  1. pdf-document
  2. pdf-image
  3. pdf-layout
  4. pdf-resume
  5. text-measure

External resources

None.

Prompts

  1. resource-fetching

Resources

  • PDFKit Documentation
  • JSON Resume Schema
  • JSON Resume Editor

Máy chủ liên quan

NotebookLM Web Importer

Nhập trang web và video YouTube vào NotebookLM chỉ với một cú nhấp. Được tin dùng bởi hơn 200.000 người dùng.

Cài đặt tiện ích Chrome