{
  "markdown": "# mcp-resume\n\n<!-- mirror-seo:start -->\n\n**MCP server for resume and cover letter writing, CV documents in Word format.** Resumes and cover letters as Word files from one profile, never invented.\n\nWorks with Claude Desktop, Claude Code, Cursor and any Model Context Protocol client. Runs on your own machine, or hosted with no install.\n\n## Install\n\n**Hosted, nothing to install.** Get a token from <https://mcp.zovo.one/mcp/connect> (the connect page) or <https://mcp.zovo.one/mcp/token> (the same token as JSON); a free anonymous one is issued on the spot and a Pro key works the same way. Then point an MCP client at `https://mcp.zovo.one/mcp/resume` over streamable-http and send the token as `Authorization: Bearer <token>`.\n\nIf your client cannot set headers, put the token in the path instead: `https://mcp.zovo.one/mcp/resume/t/<token>`. Both forms work. The bare URL with no token answers 401 on `tools/call`, so the token is not optional.\n\n**Claude Desktop, one click.** Download `resume.mcpb` from the [latest release](https://github.com/theluckystrike/mcp-servers/releases/latest) and double-click it.\n\n**From source.** The mirror is self-contained: every `@theluckystrike/*` dependency is vendored, so a fresh clone builds with no extra setup.\n\n```sh\ngit clone https://github.com/theluckystrike/mcp-resume.git\ncd mcp-resume\nnpm install && npm run build\n```\n\nThen point your client at the built entry point:\n\n```json\n{\n  \"mcpServers\": {\n    \"resume\": {\n      \"command\": \"node\",\n      \"args\": [\"/absolute/path/to/mcp-resume/dist/index.js\"]\n    }\n  }\n}\n```\n\n> `@theluckystrike/mcp-resume` is **not published on npm yet**, so an `npx -y @theluckystrike/mcp-resume` command will fail. The three paths above are the working ones and each is exercised by CI.\n\n![resume demo](https://raw.githubusercontent.com/theluckystrike/mcp-servers/main/assets/demo-resume.gif)\n\nRead-only mirror of [mcp-servers/servers/resume](https://github.com/theluckystrike/mcp-servers/tree/main/servers/resume). See [MIRROR.md](MIRROR.md).\n\n<!-- mirror-seo:end -->\n\nStore your CV facts once. Then say \"tailor my resume to this posting and write the cover letter\" and get two real\n`.docx` files: a resume whose bullets are reordered by relevance to the posting, trimmed to fit the page count you\nasked for, with the posting's keywords in bold where you actually have them -- and a one-page cover letter that\nstates nothing you did not put in your profile. Where a fact is missing, the letter leaves a bracketed prompt like\n`[add: metric]` instead of inventing a number. It also reads an existing resume `.docx` back into the profile shape,\nexports markdown for an ATS box, and writes printable HTML. Everything runs locally: no upload, no account, no\nnative dependency.\n\n\n**A resume that fits the page and a cover letter that cannot lie about you.**\n\n## 60-second install\n\nnpm publish for `@theluckystrike/mcp-resume` is pending. Until then, the `.mcpb` one-click bundle or a clone+build\nis the working path -- both are verified below.\n\n**One-click (.mcpb):** download `resume.mcpb` from the latest release and double-click it in Claude Desktop:\nhttps://github.com/theluckystrike/mcp-servers/releases/latest\n\n**Claude Desktop** (`claude_desktop_config.json`):\n\n```json\n{\n  \"mcpServers\": {\n    \"resume\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@theluckystrike/mcp-resume\"]\n    }\n  }\n}\n```\n\n**Claude Code:**\n\n```sh\nclaude mcp add resume -- npx -y @theluckystrike/mcp-resume\n```\n\n**Cursor** (`.cursor/mcp.json`):\n\n```json\n{\n  \"mcpServers\": {\n    \"resume\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@theluckystrike/mcp-resume\"]\n    }\n  }\n}\n```\n\nThe `npx` form above starts working the moment the package is published. Until then, use the .mcpb bundle above, or\nbuild from source with exactly these three commands:\n\n```sh\ngit clone https://github.com/theluckystrike/mcp-servers.git && cd mcp-servers\nnpm install\nnpm run build -w packages/mcp-license -w servers/docx -w servers/resume\n```\n\nThen point your client's `command` at `node` with one arg: the absolute path to `servers/resume/dist/index.js`.\n`servers/docx` is in that build list because this server shares the document engine with\n[mcp-docx](../docx) rather than carrying a second copy of it.\n\nTo run in Pro mode set `MCP_LICENSE_KEY` in the same config block, or call `license_activate` once with your key.\n\n## Tools\n\n| Tool | What it does |\n| --- | --- |\n| `profile_set` | Store the facts every output is built from: name, email, phone, location, links, summary, skills, roles with bullets, education, certifications, languages. One profile per data directory; Pro adds named variants |\n| `profile_get` | Return the stored profile as JSON, exactly as the other tools see it |\n| `resume_create` | Write the resume as `.docx`. Bullets are ranked by keyword hits and recency, then trimmed to `max_pages` against a measured word budget; matched keywords are bolded, missing ones are reported and never added. Styles: `modern`, `classic`, `compact` |\n| `cover_letter_create` | A one-page letter in four parts -- opening, fit, proof, close -- drawn only from the profile. Tones: `formal`, `direct`, `warm`. Unknowns come back as `[add: ...]` prompts |\n| `tailor_to_job` | Gap analysis against a posting: the keywords it actually asks for, which of them your profile already covers, which it does not, a coverage figure, and rewrites that only reorder facts you already stated |\n| `resume_read` | Read an existing resume `.docx` back into the profile shape, section by heading. Best effort; nothing is saved unless `save: true` |\n| `resume_to_markdown` | The resume as markdown, for an application form or an ATS box |\n| `resume_to_html` | Printable HTML with a print stylesheet. Open it and print to PDF |\n| `license_status` | Show free or Pro mode |\n| `license_activate` | Activate a Pro key (verified offline) |\n\nResource: `resume://profile` returns the stored profile as JSON.\nPrompt: `apply_to_job` chains `tailor_to_job`, `resume_create` and `cover_letter_create` against one posting, and\nmakes the model report the gaps back to you instead of filling them in.\n\n## The cover letter does not invent facts\n\nThis is the part that matters, so it is enforced rather than requested:\n\n- Every proof line in the letter is a **verbatim bullet from your profile**. The letter never paraphrases a\n  bullet into a stronger claim.\n- A `highlights` entry you pass is checked against the profile first. If the profile does not support it, it is\n  printed as `[add: \"...\" is not in your profile - add it there or drop it]`, not as a claim.\n- Before the file is written, every digit run in the letter is checked against your profile and the arguments you\n  passed. A number that traces to neither is a refusal, not a warning -- the tool returns an error and writes nothing.\n  The job description is deliberately **not** an allowed source: the employer's revenue, headcount and throughput\n  figures are theirs, and the letter will never restate one as yours. Comparison is on whole numbers, so a profile\n  holding `2012` does not license a letter claiming `12`.\n- Each proof bullet is printed under the role it actually belongs to. A letter that quotes work from two employers\n  prints two headings; work from an earlier job is never listed under your current one.\n- A bullet that carries no figure gets ` [add: metric]` appended, so the letter asks you for the result instead of\n  guessing one.\n- Missing keywords from `tailor_to_job` never become skills. The response says so in plain words.\n\n## What you can say\n\n| You say | Tool |\n| --- | --- |\n| \"Here is my CV: Ada Rowe, backend engineer, Acme Pay since 2021, ...\" | `profile_set` |\n| \"Read my old resume at ~/Documents/cv.docx and set up my profile.\" | `resume_read` |\n| \"How well do I match this posting?\" | `tailor_to_job` |\n| \"Make me a one-page resume for this Staff Engineer role.\" | `resume_create` |\n| \"Write the cover letter for Zeta Systems, direct tone.\" | `cover_letter_create` |\n| \"Give me the plain-text version for the application form.\" | `resume_to_markdown` |\n| \"I need a PDF to attach.\" | `resume_to_html`, then print to PDF |\n| \"Apply me to this job.\" | the `apply_to_job` prompt |\n\n## Worked example\n\n```\nYou: Tailor my resume to this posting and write the letter. One page.\n\n  tailor_to_job { job_description: \"...payments platform, PostgreSQL, Kubernetes...\" }\n  -> matched: payments, postgresql, kubernetes   missing: rust\n  -> coverage 75%\n\n  resume_create { style: \"modern\", target_role: \"Staff Engineer\",\n                  keywords: [\"postgresql\", \"kubernetes\", \"rust\"], max_pages: 1 }\n  -> estimated_pages 1, words_used 402 of a 384-word budget for bullets\n  -> bullets_dropped: [\"Wrote the deployment pipeline\"]\n  -> keywords_missing: [\"rust\"]  (not added anywhere)\n  -> ~/.local/share/mcp-servers/resume/documents/ada-rowe-resume.docx\n\n  cover_letter_create { company: \"Zeta Systems\", role: \"Staff Engineer\", tone: \"formal\" }\n  -> fills_required: [\"[add: metric]\"]\n  -> ~/.local/share/mcp-servers/resume/documents/zeta-systems-staff-engineer-cover-letter.docx\n```\n\n## How page trimming works\n\nThere is no page-layout engine in pure JavaScript, so this server does not pretend to measure one. It uses a word\nbudget instead: a full A4 page at 11pt Calibri with 2cm margins holds about 520 words of body text, and a resume\nspends roughly a seventh of that page on headings, blank lines and the contact block. The net figure is **450 words\nper page** (540 for the `compact` style). The contact block, summary, skills, role headers, education,\ncertifications and languages are counted first; whatever budget is left goes to experience bullets, highest score\nfirst. Every role keeps its first bullet before any role gets a second one, so trimming never leaves a job on the\npage with nothing under it. The response reports the budget, the words used, the estimated page count and every\nbullet it dropped, so you can see the decision rather than discover it in Word.\n\nRecency is part of that score, and it is read off array order, not off `start`/`end` text. `profile_set` enforces\nthe ordering that makes that safe: however you list roles when you call it, the stored profile always ends up\nnewest-first -- an open role with no `end` first, then by `end` descending, then by `start` descending. Enter roles\nin any order; the stored order (and the cover-letter bullet ranking in `cover_letter_create`) is always correct.\n\n## Free vs Pro\n\n| | Free | Pro ($19 one-time) |\n| --- | --- | --- |\n| Profile, `resume_create`, `resume_to_markdown`, `resume_to_html` | Yes, unlimited | Yes, unlimited |\n| Resume styles | `modern` | `modern`, `classic`, `compact` |\n| Cover letters | 3 per calendar month | Unlimited |\n| `tailor_to_job` | Postings up to 2,000 characters | Any length |\n| Profile variants | One profile | Named variants (`backend`, `management`, ...) |\n| Letterhead colour | Default | Your own `accent_color` |\n| Footer credit | \"Generated with mcp-docx by theluckystrike\" | Removed |\n\n**Get Pro:** https://mcp.zovo.one/buy/resume ($19 one-time, or $39 for the whole bundle).\n\n## Privacy\n\nAll data stays local. Your CV never leaves the machine: the server reads and writes files on your computer, stores\nthe profile under your data directory, and makes no network request of any kind -- not for licensing (keys are\nverified offline), not for fonts, not for telemetry.\n\n## Pairs with\n\n- [mcp-docx](../docx/README.md) -- this server imports its document engine (`@theluckystrike/mcp-docx/lib`); install docx too when you also want proposals, contracts and markdown-to-Word.\n- [office-suite](../office-suite/README.md) -- several servers behind one install, one config entry.\n\n## Troubleshooting\n\n- **`npx` hangs or fails to find the package**: npm publish for this package is pending. Use the `.mcpb` bundle or\n  the clone-and-build path above until it lands.\n- **\"no profile stored\"**: run `profile_set` once, or `resume_read {path, save: true}` from an existing resume.\n- **The resume dropped a bullet I wanted**: raise `max_pages`, or pass the posting's words in `keywords` so the\n  bullet outranks the others. `bullets_dropped` in the response names every one that did not fit.\n- **Short skill names**: `tailor_to_job` keeps two- and one-character skills -- `Go`, `C`, `R`, `C#`, `C++`, `F#`,\n  `Qt`, `UI`, `UX`, `QA`, `ML`, `AI`, `AR`, `VR`, `JS`, `TS`, `K8s`, `AWS`, `GCP`, `SQL`, `iOS` -- plus any short\n  word that appears in your own `skills` list, and ranks a known skill above a longer word of the same frequency.\n- **A keyword I have is reported missing**: matching is on word boundaries, so `go` does not match `Google` and\n  `k8s` does not match `Kubernetes`. Add the exact word to your skills if it is true.\n- **`resume_read` put a role in `unparsed`**: resumes have no schema. Nothing is dropped silently -- fix the fields\n  and pass them to `profile_set`.\n- **There is no `resume_to_pdf`**: every pure-JavaScript route from Word to PDF needs a native dependency or a\n  cloud API. `resume_to_html` writes semantic HTML with a print stylesheet; print that to PDF.\n- **Node version**: requires Node >= 18. Check with `node -v`.\n\nMIT licensed. Support: support@zovo.one\n\nBuilt by [theluckystrike](https://github.com/theluckystrike).\n\n## One business profile for the whole suite\n\nYour identity is stored once, at `${XDG_DATA_HOME:-~/.local/share}/mcp-servers/profile/business.json`,\nand every server in the suite reads it: the invoice issuer, the docx letterhead, the recurring\nissuer, expense-tracker's default VAT rate, time-tracker's and timezone's home zone, and the\nresume and contract letterheads. Set it once with `business_set` (invoice or docx) - you never\nrepeat it anywhere else. An email address is only ever taken from that profile or from an explicit\nargument; when none is stored, documents show `[add: email]` and the tool says so rather than\nletting anyone improvise an address.\n",
  "bytes": 13920,
  "sha": "92ec1da878f1ec303a9162099793d0ee05562488f10737f96a162db23c7855eb",
  "repo_slug": "theluckystrike/mcp-resume",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/plg_theluckystrike_mcp_resume_58ec4d38/readme"
}