MCP13 min read·

How to Build a Claude MCP Server That Generates a Resume PDF (2026)

A practical developer walkthrough for building a Model Context Protocol server that lets Claude generate a real resume PDF, from tool definitions to LaTeX or HTML rendering to serving the file back.

Anup Ojha
By · Backend & AI Developer
MCPModel Context ProtocolClauderesume PDFdeveloper guideFastAPILaTeX

Claude is excellent at writing resume content and terrible at handing you a finished PDF, because generating a compiled document is not something a language model does on its own. That gap is exactly what the Model Context Protocol was built to close. With a small MCP server you define a tool, Claude calls it with structured resume data, your code renders a real PDF, and the file comes back to the user. This is a developer walkthrough of how to build that server: the tool schema, the rendering step, and how the file gets served back. It assumes you are comfortable with a bit of Python and want the architecture, not a copy-paste blob.

Why MCP is the right tool for this

MCP is an open standard that lets an AI client, Claude Desktop, the API, or another host, discover and call tools you expose from a server. Instead of asking Claude to describe a PDF it cannot make, you give it a tool called something like generate_resume, declare the shape of the data it takes, and let Claude fill that data from a conversation. The model handles language and judgment; your server handles deterministic document generation. That separation is the whole point, and it is why MCP matters for the job hunt more broadly.

The architecture in one picture

Four moving parts, in order:

  1. Tool definition. A schema describing the resume data your tool accepts (name, contact, experience, skills, and so on).
  2. Handler. The function that runs when Claude calls the tool. It validates the input and kicks off rendering.
  3. Renderer. The step that turns structured data into a PDF, via LaTeX or HTML to PDF.
  4. Return path. How the finished file gets back to the user, usually a hosted URL.

Step 1: define the tool and its schema

The schema is the contract between Claude and your code. Keep it explicit, because the clearer the shape, the more reliably Claude fills it. A resume tool typically accepts a structured object: a header block (name, email, phone, links), a list of experience entries (company, title, dates, bullet points), an education list, and a skills list. Mark the genuinely required fields as required, give every field a plain description, and prefer arrays of objects over free-form strings so the renderer gets clean data.

In the Python MCP SDK you register the tool with its name, a human-readable description Claude uses to decide when to call it, and a JSON Schema for the input. The description is not decoration: it is how the model knows this tool exists to produce a resume PDF, so write it like an instruction, for example "Generate a print-ready resume PDF from structured resume data and return a download URL."

Step 2: write the handler

The handler is where control returns to your code. Do three things in it, in order.

  • Validate. Never trust the incoming payload blindly. Confirm the required fields exist and coerce types. A model-filled object is usually good but not guaranteed.
  • Render. Pass the validated data to your renderer and get back a file path or bytes.
  • Return a result the client can use. Hand back a URL or resource, not the raw internal path, unless you are running locally.

Keep the handler thin. Its job is orchestration, not formatting logic. Push the actual document work into the renderer so you can test and swap it independently.

Step 3: render the PDF

This is the decision that shapes everything downstream, and it comes down to LaTeX versus HTML to PDF.

LaTeX: print quality and clean extraction

LaTeX produces the sharpest typography and, done right, a PDF whose text extracts cleanly in order, which is exactly what an applicant tracking system needs. The flow is: fill a template with the resume data using a templating engine, write the resulting source to a temporary directory, run the LaTeX compiler, and read back the PDF. Two practical notes from running this in production: compile twice if your template uses references or precise spacing that settles on a second pass, and always clean up the temporary directory in a finally block so failed compiles do not leave junk behind. The cost is that you need a LaTeX toolchain installed wherever the server runs, which matters for deployment.

HTML to PDF: fast to build, easy to style

The alternative is to render an HTML template with CSS and convert it to PDF with a headless browser or a library that wraps one. You get to style with CSS you already know and skip the LaTeX install. The trade-off is less precise typographic control and a real risk of ATS-unfriendly output if you reach for multi-column layouts or background images. If you go this route, build a single-column, semantic template and test that the exported text copies out cleanly.

Whichever renderer you choose, run the extraction test: open the generated PDF, select all, copy, and paste into a plain text editor. If the text comes out clean and in reading order, an ATS can parse it. If it scrambles, no amount of visual polish will save the application. This is the same test covered in passing AI resume screening.

Step 4: get the file back to the user

MCP tools return content to the client, and for a binary like a PDF you have three sane options.

  • Return a URL. Upload the PDF to storage (a bucket, or your own file endpoint) and return a link. This keeps the response small and lets the user click to download. It is the cleanest default, especially for a hosted server.
  • Return a base64 resource. Encode the bytes and return them as an embedded resource. Fine for small files and local use, but it bloats the payload.
  • Write to a known path. For a local stdio server, write the file to an output directory and return the path. Simple, but only works when client and server share a filesystem.

For anything beyond local experimentation, prefer the URL pattern. Generate a short-lived signed URL if the file is private, so the download link works for the user without exposing your storage.

Step 5: transport and connecting to Claude

MCP servers speak over a transport. For a local tool used from Claude Desktop, stdio is the standard: you register the server in the client config and it launches your process. For a hosted server that multiple clients reach over the network, use the HTTP or SSE transport and mount it behind your web framework. A common production shape is a FastAPI app that both exposes normal HTTP endpoints and mounts the MCP server at a path, so the same rendering logic serves an API and Claude at once. Once connected, Claude sees your generate_resume tool, and a user can simply ask it to build a resume and get a PDF link back.

Common mistakes to avoid

  • Vague tool descriptions. If Claude does not reliably call your tool, the description is usually why. Make it explicit about what it does and when to use it.
  • Trusting the payload. Validate. A missing required field should fail loudly, not produce a broken PDF.
  • Ignoring ATS extraction. A beautiful PDF that scrambles on copy-paste defeats the entire purpose of a resume. Test extraction on every template.
  • Returning giant base64 blobs for a hosted server. Use URLs; keep the protocol payload light.
  • Leaving temp files behind. Clean up rendering artifacts in a finally block, or your disk fills up in production.

If you would rather not build it

Building your own MCP server is the right call when you want custom templates, full control of the data, or resume generation inside your own product. If you just want to use Claude to build and tailor resumes today, that pipeline already exists as a hosted service. ApplyJobFaster runs exactly this kind of setup, tailoring and compiling a clean resume PDF, and exposes it through MCP so you can connect it to Claude directly, which is walked through in connecting your resume to Claude with MCP. Build the server when you need the control; use the hosted one when you need the result.

Frequently Asked Questions

What is an MCP server and why use one to generate a resume PDF?+
MCP, the Model Context Protocol, is an open standard that lets an AI client like Claude call external tools you define. An MCP server for resume generation exposes a tool such as generate_resume that Claude can invoke with structured data, then returns a real PDF. It lets Claude do something it cannot do natively, produce a compiled, downloadable document, while you keep full control of the formatting and data.
What language and framework should I use to build it?+
Any language with an MCP SDK works. Python is the most common choice because the MCP SDK is mature and it pairs well with PDF tooling. A typical stack is a Python MCP server, a rendering step using LaTeX for print-quality output or headless HTML to PDF for simplicity, and optionally FastAPI if you also want to expose the same logic over HTTP.
How does Claude actually receive the generated PDF?+
MCP tools return content back to the client. For a PDF the common patterns are returning a URL to a hosted file, returning the file as a base64-encoded resource, or writing it to a known output path and returning that path. A URL is usually cleanest because it keeps the payload small and lets the user click to download.
Should I render the PDF with LaTeX or HTML?+
LaTeX gives you the cleanest typography and reliable text extraction, which matters if the resume must pass an applicant tracking system, but it needs a LaTeX toolchain installed. HTML to PDF with a headless browser is easier to set up and style with CSS, at some cost to fine typographic control. For a resume that must be ATS-parseable, LaTeX or a carefully built single-column HTML template is the safer choice.
Do I need to build this from scratch to use Claude for resumes?+
No. If you just want to use Claude to build and tailor resumes without writing a server, a hosted service already exposes this. Building your own MCP server makes sense when you want custom templates, full control of the data, or to integrate resume generation into your own product.
Anup Ojha

Anup Ojha

Backend & AI Developer · Jackson and Frank

Backend & AI engineer at Jackson and Frank. Building ApplyJobFaster - the AI pipeline that turns a LinkedIn job post into a sent application in under 60 seconds. Python · FastAPI · Gemini AI · LaTeX · Telegram bots · MCP servers.

Related Articles

Stop reading, start applying

Ready to apply smarter?

AI-tailored resume + cover email sent from your Gmail - in under 60 seconds per application.

Try ApplyJobFaster Free