Let AI agents generate PDFs with MCP (Claude Code, Cursor and more)
AI agents are good at writing HTML and Markdown, but they cannot print. Ask one for "a PDF of this report" and you usually get HTML and instructions to open it in a browser. The Model Context Protocol (MCP) fixes that by letting an agent call tools. This guide explains how to give an agent a PDF tool, first by building a small MCP server yourself, then by connecting PDFOven's hosted MCP server.
How MCP fits in
MCP is an open protocol for connecting AI applications (Claude Code, Claude Desktop, Cursor, and others) to external tools. An MCP server advertises tools with names, descriptions and input schemas. When a user asks for something, the model decides to call a tool, the client sends the call to the server, and the result comes back into the conversation.
For PDF generation, the tool takes HTML or Markdown as input and returns a rendered document.
Option 1: build your own MCP server
Using the official TypeScript SDK and Puppeteer, a minimal stdio server looks like this:
npm install @modelcontextprotocol/sdk zod puppeteer
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
import puppeteer from "puppeteer";
import { writeFile } from "node:fs/promises";
import { resolve } from "node:path";
const server = new McpServer({ name: "local-pdf", version: "1.0.0" });
server.registerTool(
"render_pdf",
{
description: "Render HTML to a PDF file on disk and return its path.",
inputSchema: { html: z.string(), filename: z.string().default("output.pdf") },
},
async ({ html, filename }) => {
const browser = await puppeteer.launch();
try {
const page = await browser.newPage();
await page.setContent(html, { waitUntil: "networkidle0" });
const pdf = await page.pdf({ format: "A4", printBackground: true });
const path = resolve(filename);
await writeFile(path, pdf);
return { content: [{ type: "text", text: "Saved " + path }] };
} finally {
await browser.close();
}
}
);
await server.connect(new StdioServerTransport());
Register it with Claude Code:
claude mcp add local-pdf -- node /absolute/path/to/server.mjs
This works well for a single developer. The trade-offs:
- Every machine that uses it needs Node and a Chromium download, and Chromium's memory footprint lands on the developer's laptop or the agent's sandbox.
- It is a local stdio server, so cloud-hosted agents and teammates cannot share it without you deploying and securing it as a remote service.
- Writing to arbitrary filenames chosen by a model is risky. Restrict the output directory in real use.
- Agent-written HTML can reference any URL, so the same SSRF concerns apply as with any headless browser that renders untrusted content.
Option 2: PDFOven's hosted MCP server
PDFOven runs a remote MCP server at https://pdfoven.com/mcp using the Streamable HTTP transport, authenticated with your API key as a bearer token. It exposes three tools:
render_pdf: render HTML, Markdown, a URL, or a template with data to PDF.render_image: render the same inputs to PNG or JPEG.list_templates: list your saved templates so the agent can fill one with data instead of writing HTML from scratch.
Rendering happens on PDFOven's Chromium fleet, so nothing heavy runs on your machine, and the same configuration works for every teammate.
Claude Code
Export your key, then add the server:
export PDFOVEN_KEY=po_live_your_key_here
claude mcp add --transport http pdfoven https://pdfoven.com/mcp --header "Authorization: Bearer $PDFOVEN_KEY"
Run claude mcp list to confirm it connected. Then ask naturally:
Turn CHANGELOG.md into a nicely styled A4 PDF with page numbers in the footer.
Use my invoice template to create an invoice for Globex: 6 hours of consulting at $150.
Render the pricing section of our landing page as a 1200x630 PNG.
Cursor
Add the server to .cursor/mcp.json in your project (or the global ~/.cursor/mcp.json):
{
"mcpServers": {
"pdfoven": {
"url": "https://pdfoven.com/mcp",
"headers": { "Authorization": "Bearer po_live_your_key_here" }
}
}
}
Do not commit a file containing a live key. Keep it in the global config or add the project file to .gitignore.
Other clients
Any MCP client that supports Streamable HTTP servers with custom headers can connect using the same URL and Authorization: Bearer header. Clients that only support local stdio servers can use a stdio-to-HTTP bridge such as mcp-remote.
Tips for good agent-generated PDFs
- Prefer templates for repeat documents. Save an invoice, quote or report template once; the agent calls
list_templatesand only supplies data. Output stays on-brand and the model has less to get wrong. Templates support helpers such ascurrency,date,sumandlineTotal. - Ask for Markdown for prose. Markdown plus a short CSS string is less error-prone for a model than a full HTML document.
- Be explicit about paper. Mention A4 or Letter, orientation and margins in your prompt; they map directly to the tool's options.
- Mind your quota. Each tool call is a render. On the free plan (100 renders per month) an agent iterating on a design can use renders quickly. When the quota is exhausted the server reports a
quota_exceedederror, which the agent will relay. Paid plans are $12, $39 and $99 for 2,000, 15,000 and 60,000 renders.
Security notes
- Treat the API key like any credential. Use a dedicated key for agents so you can rotate it independently.
- PDFOven does not store rendered files, so documents generated by agents are not retained on our side after the response is returned.
- Review what an agent puts in a document before sending it to customers. A tool makes rendering easy; it does not make the content correct.
Without MCP
If your agent framework calls HTTP APIs directly rather than MCP, the same capabilities are available at POST https://pdfoven.com/v1/pdf and POST https://pdfoven.com/v1/image; see the Node.js guide for request examples. And for one-off documents, the free HTML to PDF and Markdown to PDF tools need no setup at all.
Skip the browser plumbing
PDFOven runs Chromium for you. Send HTML, Markdown, a URL or JSON to a template and get a PDF back. 100 free renders every month.
Get a free API key