Skip to main content
Glama
README.md
# 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

A4.2/5.0

Scored across 5 tools

Disambiguation5/5

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.

Naming Consistency4/5

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.

Tool Count5/5

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.

Completeness5/5

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.

Maintenance

ActivityInactive
ResponsivenessNo issues