Metadata-Version: 2.4
Name: cv-tailor-mcp
Version: 0.2.0
Summary: MCP server that tailors a LaTeX one-page CV to a job posting without burning tokens on boilerplate or compile-log babysitting.
Author: Aarón Ugalde Téllez
License-Expression: MIT
Project-URL: Homepage, https://github.com/AaronUgalde/cv-tailor-mcp
Project-URL: Repository, https://github.com/AaronUgalde/cv-tailor-mcp
Project-URL: Issues, https://github.com/AaronUgalde/cv-tailor-mcp/issues
Keywords: mcp,cv,resume,latex,cursor
Classifier: Development Status :: 4 - Beta
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: mcp>=1.0
Requires-Dist: jinja2>=3.1
Requires-Dist: pyyaml>=6.0
Dynamic: license-file

# cv-tailor-mcp

An MCP server that tailors a one-page LaTeX CV to a specific job posting
without burning tokens on repetitive work: re-reading your whole CV source,
writing the same LaTeX boilerplate over and over, or pasting `pdflatex`
compiler logs into the chat.

It works identically from **Claude Code** and **Cursor** (or any other
MCP-compliant client) -- MCP is an open protocol, so the same server binary
is just registered in each client's own config file.

**This repo contains no personal data.** You keep your own `cv_facts.yaml`
(your real experience/projects/skills) in your own private repo, and point
this server at it via environment variables. See
[`cv_tailor_mcp/examples/cv_facts.example.yaml`](cv_tailor_mcp/examples/cv_facts.example.yaml) for a
fictional but complete example, and [`docs/SCHEMA.md`](docs/SCHEMA.md) for
the full schema.

## What it does

Instead of:
1. Reading your entire CV source file into the model's context every time,
2. reading a previous tailored variant as a style reference,
3. having the model write ~150-250 lines of near-identical LaTeX by hand, and
4. pasting compiler output into the chat 3-5 times while manually tightening
   spacing to fit one page...

...you get a small set of tool calls:

| Tool | Purpose |
|---|---|
| `list_tags` | Discover the tags in your `cv_facts.yaml` |
| `get_facts(tags=[...])` | Get only the relevant slice of your experience/projects/skills |
| `list_variants` | See CVs you've already generated (tagline, tags) without re-reading each file |
| `render_cv(payload)` | Generate `cv_<variant>.tex` from ids, with optional per-CV bullet rewrites that never modify `cv_facts.yaml` |
| `compile_cv(variant)` | Run `pdflatex`, get back `{success, pages, first_error}`, auto-cleans `.aux`/`.log`/etc. |

There's no automatic "shrink until it fits one page" tool in v1 -- if
`compile_cv` reports 2 pages, call `render_cv` again with
`spacing_profile: "compact"` or `"tight"` (see [`docs/SCHEMA.md`](docs/SCHEMA.md)).

## Install

Requires Python 3.10+. A LaTeX distribution is optional during setup:
without `pdflatex`, the MCP can still generate `.tex` files and reports a
clear error if `compile_cv` is called.

```bash
git clone https://github.com/AaronUgalde/cv-tailor-mcp.git
cd cv-tailor-mcp
./setup.sh
```

The setup script:

1. Installs the command in a project-local virtual environment.
2. Creates `~/.cv-tailor/cv_facts.yaml` with fictional starter data.
3. Creates `~/.cv-tailor/generated/`.
4. Safely adds `cv-tailor` to `~/.cursor/mcp.json`, preserving other servers.

It never replaces an existing facts file or `cv-tailor` MCP entry unless you
explicitly pass `--force`.

Next, replace the fictional information in `~/.cv-tailor/cv_facts.yaml`,
restart Cursor, and ask it to call `list_tags`.

### Install as a user command

The project is packaged for PyPI. After publishing it, users can install it
as an isolated command with:

```bash
uv tool install cv-tailor-mcp
cv-tailor-mcp init
```

`pipx install cv-tailor-mcp` works as an alternative to `uv`.

Useful setup options:

```bash
cv-tailor-mcp init --no-cursor
cv-tailor-mcp init --facts-path ~/private-cv/facts.yaml --output-dir ~/CVs
cv-tailor-mcp doctor
```

`cv-tailor-mcp serve` starts the stdio server and is normally invoked by
Cursor rather than run manually.

## Configuration

### Environment variables

| Variable | Required | Default |
|---|---|---|
| `CV_FACTS_PATH` | yes | -- |
| `CV_OUTPUT_DIR` | yes | -- |
| `CV_TEMPLATE_PATH` | no | bundled `cv_tailor_mcp/templates/default_cv_template.tex.j2` |
| `PDFLATEX_PATH` | no | resolved via `PATH` (`shutil.which("pdflatex")`) |

The server fails fast if the facts or output paths are missing. A missing
`pdflatex` only disables `compile_cv`; all other tools remain available.

Other MCP clients can use the command and environment variables generated in
Cursor's `mcp.json`. The transport is standard MCP over stdio.

## Example session

```
> list_tags
{"tags": [{"name": "backend", "experience": 1, "projects": 1, ...}, ...]}

> get_facts(tags=["backend", "cloud"])
{... only the entries/bullets tagged backend or cloud ...}

> render_cv({
    "variant": "acme",
    "tagline": "Backend Engineering Intern Candidate",
    "summary": "...",
    "skill_group_ids": ["languages", "backend_cloud"],
    "experience": [{
      "id": "acme_backend_intern",
      "bullet_ids": ["acme_api_bullet", "acme_pipeline_bullet"],
      "bullet_overrides": {
        "acme_api_bullet": "Tailored, LaTeX-ready wording for this CV only."
      }
    }],
    "projects": [{"id": "proj_taskflow", "bullet_ids": ["taskflow_realtime_bullet"]}]
  })
{"tex_path": ".../cv_acme.tex", "line_count": 118, "spacing_profile": "default"}

> compile_cv("acme")
{"success": true, "pages": 1, "first_error": null}
```

## Bring your own template

If the bundled one-page style doesn't match yours, write your own
`.tex.j2` (Jinja2, using `<< >>` for variables and `<% %>` for blocks/loops
instead of the default `{{ }}`/`{% %}`, since LaTeX already uses `{`/`}`) and
point `CV_TEMPLATE_PATH` at it. It must accept the same context documented in
[`docs/SCHEMA.md`](docs/SCHEMA.md) -- see
[`cv_tailor_mcp/templates/default_cv_template.tex.j2`](cv_tailor_mcp/templates/default_cv_template.tex.j2)
for a working reference.

## Scope / non-goals for v1

- No auto-fit-to-one-page spacing tool -- three manual `spacing_profile`
  presets instead (see above).
- `cv_facts.yaml` remains the immutable source of truth from the MCP's
  perspective. `render_cv` can tailor selected bullets through
  `bullet_overrides`, but those rewrites only affect the generated CV.
- `compile_cv` only confirms the page count pdflatex reports -- it doesn't
  check whether the result *looks* good. Open the PDF yourself before you
  send it anywhere.

## License

MIT, see [LICENSE](LICENSE).
