Lathe
# Lathe
> Local MCP server that shapes tailored resume PDFs with a live browser preview.
Lathe is a small [Model Context Protocol](https://modelcontextprotocol.io) server you run on your own machine. You talk to Claude about your background, your target job, and the kind of resume you want; Claude shapes the content; Lathe renders it in a real browser window that updates as you iterate. When you're happy, Lathe exports a print-ready PDF.
Nothing about you leaves your laptop.
## Why this exists
A lot of resume MCPs ship your data to a third-party API to render the PDF. The most popular one (`resumake-mcp`) depends on an upstream service that's been shut down, and pins a vulnerable version of the MCP SDK. Lathe takes the opposite approach: render everything locally with headless Chromium, no external services, no accounts.
## Features
- **Live preview** — A Chromium window opens on first use and stays put. Every edit Claude pushes refreshes the page in place, so you watch the resume change as you give feedback.
- **HTML/CSS templates** — Three starter templates (`modern`, `classic`, `minimal`). Hand-write your own, or describe one in chat and let Claude generate it.
- **Print-ready PDF** — `letter` paper, real CSS, real fonts. Exported on demand.
- **Local-first** — No third-party APIs. No accounts. Your data stays on your machine.
- **Strict TypeScript** — `strict: true`, `noUncheckedIndexedAccess: true`.
- **Zero secrets** — no env vars, no keys, no auth.
## How it works
```
You ────▶ Claude ────▶ Lathe MCP ──▶ Handlebars render ──▶ work/current.html
│
▼
Puppeteer Chromium
(visible window)
│
────▶ page.reload() ◀──┘
│
▼
You see it change
│
▼
"Export it"
│
▼
output/*.pdf
```
## Install
```bash
git clone https://github.com/itonskie/lathe.git
cd lathe
npm install # also downloads a Chromium for Puppeteer (~170 MB on first install)
npm run build
```
Then add Lathe to your Claude Desktop config:
**macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json`
**Windows:** `%APPDATA%\Claude\claude_desktop_config.json`
**Linux:** `~/.config/Claude/claude_desktop_config.json`
**Recommended (works with nvm / fnm / system node):**
```json
{
"mcpServers": {
"lathe": {
"command": "/absolute/path/to/lathe/bin/lathe.sh",
"args": []
}
}
}
```
The wrapper script in `bin/lathe.sh` sources nvm if it's installed, so it survives `nvm install` upgrades.
**System-node alternative (no wrapper):**
```json
{
"mcpServers": {
"lathe": {
"command": "node",
"args": ["/absolute/path/to/lathe/dist/server.js"]
}
}
}
```
Only works if `node` is on Claude Desktop's PATH — i.e., installed via Homebrew or system package manager, not nvm. (Claude Desktop spawns subprocesses with a minimal PATH that doesn't see `~/.nvm/`.)
Fully quit Claude Desktop (⌘Q on macOS — closing the window isn't enough) and reopen. Lathe shows up in the tools list.
## Usage
Talk to Claude naturally:
> *"Here's my background [paste]. I'm applying for this Senior Backend Engineer role at Stripe [paste JD]. Use the modern template, open the preview, and let's iterate."*
Claude will:
1. Call `lathe_templates` to confirm what's available.
2. Extract a structured resume from your inputs.
3. Call `lathe_preview` — a Chromium window opens with your resume.
4. You give feedback in chat ("make the first Acme bullet stronger", "drop the GPA").
5. Claude calls `lathe_shape` after each round — the window auto-refreshes.
6. When it looks right, ask for the PDF — Claude calls `lathe_finish`.
## Tools
| Tool | What it does |
|---|---|
| `lathe_templates` | List templates in `templates/` |
| `lathe_preview(data, template)` | Render + open the live browser window |
| `lathe_shape(data, template?)` | Push updates; browser auto-refreshes |
| `lathe_finish(filename?, folderPath?)` | Export the current preview as PDF |
| `lathe_add_template(name, html)` | Save a new template |
## Templates
Templates are plain HTML files in `templates/`, with [Handlebars](https://handlebarsjs.com) placeholders:
```html
<h1>{{basics.name}}</h1>
{{#each work}}
<div>
<strong>{{position}}</strong> at {{company}}
<ul>{{#each highlights}}<li>{{this}}</li>{{/each}}</ul>
</div>
{{/each}}
```
One custom helper is registered: `{{join keywords ", "}}` — joins an array with a separator.
Templates assume this data shape, but any field is optional:
```ts
{
basics: { name, headline, email, phone, location, website, summary }
work: [{ company, position, location, startDate, endDate, highlights[] }]
education:[{ institution, area, studyType, location, startDate, endDate, gpa }]
skills: [{ name, keywords[] }]
projects: [{ name, description, url, keywords[], highlights[] }]
}
```
To add a template, drop an HTML file into `templates/`, or have Claude generate one and save it via `lathe_add_template`.
## Development
```bash
npm run dev # tsx watch — restart on save
npm run typecheck # strict tsc check
npm test # smoke test: render all templates + export PDFs (no visible browser)
npm run build # compile to dist/
```
## Project layout
```
lathe/
├── src/
│ ├── server.ts # MCP wiring (tool registration, transport)
│ └── lathe.ts # Core: render + Puppeteer + PDF
├── templates/ # HTML templates (Handlebars)
├── test/smoke.ts # End-to-end render + PDF test
├── work/ # Rendered HTML lives here (gitignored)
├── output/ # Exported PDFs (gitignored)
└── dist/ # Compiled JS (gitignored)
```
## License
MIT © 2026 itonskie
TDQS
Scored across 5 tools
Each tool has a distinct purpose: listing templates, creating a live preview, updating the preview, exporting to PDF, and adding new templates. There is no overlap or ambiguity between them.
All tools share the 'lathe_' prefix and use snake_case, but the first tool 'lathe_templates' uses a noun instead of a verb, while others use verbs like 'preview', 'shape', 'finish', and 'add_template'. This minor inconsistency is easy to overlook.
Five tools cover the complete workflow of template management, previewing, iterative updates, and PDF export. The count is well-scoped and each tool contributes a necessary function.
The tool set covers the full lifecycle: discover templates, preview, edit data, export, and add custom templates. There are no obvious missing operations for the intended resume rendering use case.