Skip to main content
Glama

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 examples/cv_facts.example.yaml for a fictional but complete example, and 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 5 small 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 bullet/project/skill-group ids -- never fabricates, errors on unknown ids

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).

Related MCP server: LaTeX Resume MCP

Install

Requires Python 3.10+ and a LaTeX distribution (pdflatex on your PATH, or set PDFLATEX_PATH explicitly).

git clone https://github.com/<you>/cv-tailor-mcp.git
cd cv-tailor-mcp
./setup.sh

This creates a local .venv/ and installs the server into it.

Set up your own CV data

  1. Copy the example somewhere outside this repo (e.g. into your own private CV repo) and fill it in with your real information:

    cp examples/cv_facts.example.yaml ~/my-cv/cv_facts.yaml
  2. Edit it -- see docs/SCHEMA.md for the full field reference. Only put things that are actually true; the point of render_cv's id-based lookup is that it can't fabricate content that isn't in this file.

Register the server

Both Claude Code and Cursor read the same shape of config -- just a different file path:

Claude Code -- .mcp.json in your project root (or ~/.claude.json for a user-wide server):

{
  "mcpServers": {
    "cv-tailor": {
      "command": "/absolute/path/to/cv-tailor-mcp/.venv/bin/python",
      "args": ["/absolute/path/to/cv-tailor-mcp/server.py"],
      "env": {
        "CV_FACTS_PATH": "/absolute/path/to/your/cv_facts.yaml",
        "CV_OUTPUT_DIR": "/absolute/path/to/where/you/want/generated/cvs"
      }
    }
  }
}

Cursor -- the same mcpServers block in .cursor/mcp.json (project) or ~/.cursor/mcp.json (global).

Environment variables

Variable

Required

Default

CV_FACTS_PATH

yes

--

CV_OUTPUT_DIR

yes

--

CV_TEMPLATE_PATH

no

bundled templates/default_cv_template.tex.j2

PDFLATEX_PATH

no

resolved via PATH (shutil.which("pdflatex"))

The server fails fast with a clear message on startup if a required variable is missing or points at something that doesn't exist -- it never silently falls back to guessing.

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"]}],
    "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 -- see 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 is a second source of truth: if your real experience changes, update it yourself. Nothing syncs it from anywhere automatically.

  • 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.

A
license - permissive license
-
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

View all related MCP servers

Related MCP Connectors

  • Tailor resumes, generate cover letters, render CVs as PDF, and browse 22+ templates.

  • Turn a description into a shareable, editable PDF — invoices, certificates, reports, resumes.

  • Generate PDFs from templates via AI chat. Works with Claude, ChatGPT, Cursor, and any MCP client.

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/AaronUgalde/cv-tailor-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server