The Model Context Protocol (MCP) is an open standard that lets AI agents call external tools, APIs, and databases through a single interface. Anthropic released MCP in November 2024, and by March 2026, every major AI client supports it: Claude Desktop, Claude Code, ChatGPT, Cursor, VS Code, and Windsurf.
This article explains what MCP is, how the protocol works under the hood, and how to connect any AI agent to PDF4.dev's MCP server to generate PDFs with natural language.
What problem does MCP solve?
Before MCP, connecting an AI agent to an external service meant one of two things: paste the API documentation into the prompt and hope the model generates correct HTTP requests, or write custom function-calling schemas for every tool you want the model to use.
Both approaches break down:
- Pasting API docs wastes context window tokens and the model still hallucinates endpoints that don't exist
- Function calling requires developers to define schemas manually, keep them in sync, and handle auth in custom code
- Every AI client (Claude, ChatGPT, Cursor) had its own plugin or tool format, so integrations weren't portable
MCP fixes this by standardizing how AI clients discover and call tools. The AI client connects to a server, asks "what tools do you have?", gets back typed schemas, and calls them directly. No prompt engineering, no manual schemas, no client-specific code.
How MCP works: the architecture
MCP uses a client-server model with three roles:
| Role | What it does | Example |
|---|---|---|
| Host | The AI application the user interacts with | Claude Desktop, Cursor, VS Code |
| Client | Manages the connection to MCP servers (built into the host) | Built into Claude, Cursor, etc. |
| Server | Exposes tools, resources, and prompts over a standard protocol | PDF4.dev, GitHub, Notion, Slack |
The communication flow:
- The host starts up and reads its MCP config (a JSON file listing server URLs)
- The client connects to each server and calls
tools/listto discover available tools - Each tool comes with a name, description, input schema (JSON Schema), and annotations (
readOnlyHint,destructiveHint) - When the user asks a question, the AI model sees the tool list and decides which tools to call
- The client sends a
tools/callrequest to the server with the tool name and arguments - The server executes the action and returns the result
Transport: STDIO vs Streamable HTTP
MCP supports two transport protocols:
| Transport | Use case | How it works |
|---|---|---|
| STDIO | Local servers | The host launches the server as a child process and communicates via stdin/stdout |
| Streamable HTTP | Remote servers | The client sends HTTP POST requests to the server URL |
PDF4.dev uses Streamable HTTP. This means you don't need to install anything locally. Your AI client sends requests to https://pdf4.dev/api/mcp over HTTPS, just like any web API.
Tool annotations: how AI agents decide what's safe to call
Every MCP tool can include annotations that tell the AI agent how to handle it:
| Annotation | Meaning |
|---|---|
readOnlyHint: true | This tool only reads data, never modifies anything |
destructiveHint: true | This tool deletes data (the agent should confirm with the user first) |
idempotentHint: true | Calling this tool twice with the same input produces the same result |
openWorldHint: true | This tool accepts arbitrary input (like raw HTML) |
PDF4.dev sets these annotations on all 14 tools. For example, list_templates is read-only, delete_template is destructive, and render_pdf is idempotent with open-world input. This lets AI agents like Claude auto-approve safe operations and prompt the user before destructive ones.
MCP vs function calling vs API calls
| Direct API call | Function calling | MCP | |
|---|---|---|---|
| Discovery | Developer reads docs | Developer writes schemas | Automatic via tools/list |
| Auth | Developer writes auth code | Developer writes auth code | Config file (once) |
| Portability | N/A | Client-specific | Works across all MCP clients |
| Schema sync | Manual | Manual | Server is the source of truth |
| User experience | Developer writes code | Developer writes code | Natural language |
The key difference: with MCP, the server owns the tool definitions. When PDF4.dev adds a new tool, every connected AI client sees it automatically on the next connection. No SDK update, no schema change, no redeployment.
What tools does the PDF4.dev MCP server expose?
PDF4.dev's MCP server at https://pdf4.dev/api/mcp exposes 14 tools:
| Tool | What it does | Annotations |
|---|---|---|
get_info | Account overview: templates, variables, usage stats | read-only |
render_pdf | Generate a PDF from a template or raw HTML | idempotent, open-world |
preview_template | Render a template as a PNG screenshot | read-only, open-world |
list_templates | List all saved templates with variables | read-only |
get_template | Get a template's full HTML and settings | read-only |
create_template | Create a new HTML template | write |
update_template | Update a template's HTML, name, or data | idempotent |
delete_template | Permanently delete a template | destructive |
list_components | List reusable components (headers, footers, blocks) | read-only |
get_component | Get a component's HTML | read-only |
create_component | Create a reusable component | write |
update_component | Update a component | idempotent |
delete_component | Delete a component | destructive |
list_logs | View PDF generation history | read-only |
Every tool accepts an optional api_key parameter as a fallback, but the recommended approach is to pass your API key in the Authorization header of the MCP config. This way, the key is sent at the transport level and never appears in the AI model's context.
How to connect your AI client to PDF4.dev
Step 1: get an API key
Sign up at pdf4.dev and go to Dashboard > Settings to create an API key. The key starts with p4_live_ and is shown only once.
Step 2: add the MCP server config
Choose your AI client and add the config:
{
"mcpServers": {
"pdf4dev": {
"url": "https://pdf4.dev/api/mcp",
"headers": {
"Authorization": "Bearer p4_live_YOUR_KEY"
}
}
}
}Config file locations:
| Client | Config file path |
|---|---|
| Claude Desktop | ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) |
| Claude Code | Managed by CLI (stored in ~/.claude.json) |
| Cursor | .cursor/mcp.json in your project root |
| VS Code | .vscode/settings.json in your project |
| Windsurf | ~/.codeium/windsurf/mcp_config.json |
| ChatGPT | Settings UI (no file to edit) |
Step 3: verify the connection
After adding the config, restart your AI client. Then ask:
"Show me my PDF4.dev account overview"
The AI agent should call the get_info tool and return your templates, variables, and usage stats. If you see an authentication error, double-check your API key.
Example: generate an invoice PDF with natural language
Once connected, generating a PDF is a conversation:
You: "Create an invoice template with fields for company name, client name, invoice number, line items (description, quantity, unit price), and a total. Use a clean, professional design with a blue header."
The AI agent calls create_template with the HTML it generates, including {{company_name}}, {{client_name}}, {{#each line_items}}, and other Handlebars variables.
You: "Generate a PDF using that template for Acme Corp, client John Smith, invoice #INV-2026-042, with 3 line items: consulting (10h at $150), development (20h at $200), and design (5h at $100)."
The agent calls render_pdf with the template ID and the data object. You get back a PDF.
You: "The header looks too tall. Make it more compact and add a subtle gray border at the bottom."
The agent calls get_template to read the current HTML, modifies it, then calls update_template. You can preview with preview_template before generating the final PDF.
This entire flow happens through MCP tools. The AI agent never makes raw HTTP requests. It never needs to know the API endpoint structure or authentication format.
What happens under the hood during a render
When an AI agent calls the render_pdf tool, here's the sequence:
- MCP transport: the client sends a
tools/callJSON-RPC request over HTTPS tohttps://pdf4.dev/api/mcp - Auth: the server reads the
Authorization: Bearerheader, hashes the API key with SHA-256, and looks it up in the database - Template resolution: if
template_idis provided, the server fetches the HTML template and any attached header/footer components - Handlebars compilation:
Handlebars.compile(html)(data)replaces all{{variables}},{{#each}}loops, and{{#if}}blocks - Component injection:
<pdf4-header>,<pdf4-footer>, and<pdf4-block>tags are replaced with compiled component HTML - DOM restructure: the HTML is restructured into a
<table>with<thead>(header) and<tfoot>(footer) so Chromium repeats them on every printed page - Chromium render: a headless Chromium instance (Playwright) loads the page and calls
page.pdf()with the format settings - Response: the PDF buffer is base64-encoded and returned as an MCP tool result with metadata (size, duration)
The entire render takes 200-500ms with a warm browser pool.
Building your own MCP server vs using a hosted one
You can build your own MCP server using the official SDK in Python or TypeScript. This makes sense when:
- You need to connect an AI agent to an internal tool or database
- You want full control over the tool definitions
- Your data can't leave your infrastructure
For PDF generation, a hosted MCP server like PDF4.dev's is simpler because:
- Headless Chromium is notoriously hard to run in serverless environments
- PDF rendering requires a browser pool, font loading, and consistent output across OS versions
- Template management, component reuse, and generation logs are handled for you
You can also use both approaches: a local MCP server for internal tools and a remote MCP server for PDF generation.
Security considerations
MCP connections carry the same security implications as any API integration:
- API keys: stored in your local config file, never sent to the AI model's context. The MCP client sends them as HTTP headers directly to the server
- Tool confirmation: destructive tools (like
delete_template) are annotated withdestructiveHint: true, so AI clients can prompt before executing - Scope control: PDF4.dev API keys have two permission levels.
render_onlykeys can only generate PDFs.full_accesskeys can also manage templates, components, and logs - No data persistence: raw HTML sent via
render_pdfis not stored unless you explicitly save it as a template
What's next for MCP
The MCP specification is evolving. Recent additions include tool annotations (March 2025), Streamable HTTP transport, and improved error handling. Google Cloud, OpenAI, and Microsoft have all adopted the protocol, making it the de facto standard for AI-to-tool communication.
For PDF generation, this means any new AI client that supports MCP can connect to PDF4.dev without any integration work. The MCP server is the integration.
Convert HTML to PDF, freeTry it freeFree tools mentioned:
Start generating PDFs
Build PDF templates with a visual editor. Render them via API from any language in ~300ms.