← Back to blog

AI agents can generate PDFs now

A Model Context Protocol server that lets Claude, Cursor, and other AI tools render real PDFs from natural language. No code, no docs, no setup.

Ask an AI agent to generate a PDF and watch what happens. It'll write some HTML, maybe try to call a Puppeteer script, probably hallucinate an API that doesn't exist. The output, if you get one, will be a screenshot of a web page pretending to be a document.

PDFs are a binary format. They have cross-reference tables, font subsetting, stream objects, precise byte offsets. No LLM is going to produce that from a prompt. The model needs a tool.

So we built one.

The MCP server

Add this to your MCP config:

{
  "mcpServers": {
    "forme": {
      "command": "npx",
      "args": ["@formepdf/mcp"]
    }
  }
}

Restart your AI tool. Now say:

"Generate an invoice for Acme Corp. 10 hours of consulting at $150/hour, 5 hours of design at $200/hour. Tax rate 8%."

The agent calls render_pdf, passes structured data to the invoice template, and the Rust engine returns a real PDF file. Correct layout, proper page breaks, subset fonts, the works.

No code written. No docs read. No dependencies installed. The agent figured out the schema from the tool definition, structured the data, and called the render function.

Four tools

The server exposes four tools through MCP:

list_templates returns the available templates with field summaries. The agent calls this first to see what's available.

get_template_schema returns the full JSON Schema and an example for a specific template. This is how the agent knows what data shape to construct. It sees that an invoice needs company, customer, items[], total, and it builds the object from the user's natural language request.

render_pdf takes a template name and data, renders the PDF, writes it to disk, and returns the file path. This is the main tool.

render_custom_pdf takes arbitrary JSX as a string. The agent writes Forme JSX on the fly, the server transpiles it with esbuild, evaluates it, and renders to PDF. For when the built-in templates don't cover the use case.

What the agent actually does

When you say "make me a shipping label from Seattle to New York, 3 pounds, fragile," the agent:

  1. Calls list_templates to see what's available
  2. Sees shipping-label in the list
  3. Calls get_template_schema for shipping-label to get the exact data shape
  4. Constructs the data object from your request
  5. Calls render_pdf with the template and data
  6. Returns the file path

The agent reads the schema, not documentation. The tool definitions are the documentation.

The custom rendering tool

The built-in templates cover invoices, receipts, reports, letters, and shipping labels. But the render_custom_pdf tool lets the agent write any layout:

"Create a certificate of completion for Jane Smith, who completed the Advanced React course on March 15, 2026. Make it landscape with a decorative border."

The agent writes JSX:

<Document>
  <Page size="Letter" orientation="landscape" margin={40}>
    <View style={{ border: '3px solid #1a365d', padding: 60, height: '100%', justifyContent: 'center', alignItems: 'center' }}>
      <Text style={{ fontSize: 36, color: '#1a365d' }}>Certificate of Completion</Text>
      <Text style={{ fontSize: 24, marginTop: 30 }}>Jane Smith</Text>
      <Text style={{ fontSize: 16, marginTop: 20, color: '#666' }}>Advanced React Course</Text>
      <Text style={{ fontSize: 14, marginTop: 10, color: '#999' }}>March 15, 2026</Text>
    </View>
  </Page>
</Document>

The server transpiles the JSX, evaluates it, renders the PDF. The agent never touched CSS print rules or binary formats. It wrote a component and got a document.

Works in any AI tool

The server uses the Model Context Protocol, which means it works with any tool that supports MCP:

  • Claude Code
  • Cursor
  • Windsurf
  • Any custom agent using the MCP SDK

The same config, the same tools, the same experience across all of them.

Why this matters

Today, when AI agents need to produce documents, they generate Markdown. Maybe HTML. The output is always a web format because that's what the models know how to produce. But the real world runs on PDFs. Contracts, invoices, reports, certificates, shipping labels. The gap between "AI can write content" and "AI can produce a professional document" is the rendering step.

The MCP server closes that gap. The agent handles content and structure. The engine handles layout and rendering. Each does what it's good at.

Install

npx @formepdf/mcp

Or add to your MCP config and restart. The server installs on first run.

GitHub | Docs