not-boring-resume-mcp
This server helps you tailor and render professional resumes and cover letters as PDFs, adapting them to specific job offers.
Load CV (
load_cv): Read acv.yamlfile with the embedded base64 photo stripped out, returning clean YAML ready for AI tailoring (the photo is reattached automatically when rendering).Fetch job offer (
fetch_offer): Scrape a job posting URL (including JavaScript-heavy job boards) to extract visible text for tailoring.Generate CV PDF (
generate_pdf): Render a tailored YAML resume into a one-page PDF via local headless Chromium, with overflow detection so you can shorten content and re-render if needed.Generate cover letter PDF (
generate_letter_pdf): Convert a Markdown cover letter (provided inline or from a file) into a clean A4 PDF — no Word or extra dependencies required.Tailor CV (prompt): Customize your resume to a job offer and produce the PDF.
Tailor CV + cover letter (prompt): Also write and render a cover letter from a Markdown template using
[[TAILOR: ...]]markers, saving all outputs under./output/[company]/[offer]/.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@not-boring-resume-mcprender my resume.yml to a PDF"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
not-boring-resume-mcp
MCP server that renders a YAML CV into a one-page PDF via
notboringresume.cloud (local headless Chromium).
Optionnaly it can also generate a cover letter adapted to the resume and the offer.
Installation
Requires uv. First download the browser Playwright uses to render PDFs (one-time):
uvx --from not-boring-resume-mcp playwright install chromiumClaude Code:
claude mcp add not-boring-resume -- uvx not-boring-resume-mcpClaude Desktop — add to claude_desktop_config.json:
{
"mcpServers": {
"not-boring-resume": {
"command": "uvx",
"args": ["not-boring-resume-mcp"]
}
}
}Related MCP server: Resume-Tailor MCP Server
Usage
Run Claude from a folder that holds your cv.yaml (and, optionally, a
cover-letter-template.md). Then call one of the prompts:
/mcp__not-boring-resume__tailor_cv— tailor the CV and rendercv.pdf/mcp__not-boring-resume__tailor_cv_and_letter— also write and render the cover letter
The offer argument
Both prompts take the job offer as their argument — pass it right after the prompt name, either as plain text (paste the whole job description) or as a URL:
/mcp__not-boring-resume__tailor_cv https://example.com/jobs/data-engineer
/mcp__not-boring-resume__tailor_cv_and_letter <paste the full offer text here>When you give a URL, the server fetches the page and extracts its visible text before tailoring. The offer is what the CV (and letter) get adapted to, so the more complete it is, the better the result.
Both prompts also accept optional path arguments if your files aren't in the
default location: cv_path (defaults to ./cv.yaml) and, for
tailor_cv_and_letter, cover_letter_path (defaults to ./cover-letter-template.md).
Results are saved under ./output/[company]/[offer]/ (cv.pdf, the adapted cv.yaml,
and, when requested, the cover letter as .md and .pdf).
The cv.yaml file
This is the only required input. You can download a ready-to-edit template from
notboringresume.cloud (use the editor there to
build one, then save it as cv.yaml), or start from the skeleton below and fill in
your own data. Markdown is supported in the free-text fields (description,
about.description) — e.g. **bold** and [links](https://...).
profile:
name: Jane Doe
position: Data & Software Engineer
image: >- # optional: data:image/jpeg;base64,...
data:image/jpeg;base64,<...>
contact:
mail: jane.doe@example.com
city: Taipei, Taiwan
linkedin:
title: LinkedIn
url: https://linkedin.com/in/jane-doe/
github:
title: GitHub
url: https://github.com/janedoe
skills:
- categoryName: Data Engineering
skills:
- Spark
- Airflow
- DBT
- categoryName: Languages
skills:
- Python
- SQL
certifications:
- name: AWS Certified Data Analyst Specialty (2021)
languages:
- name: English
level: Fluent
- name: Spanish
level: Intermediate
about:
description: >
Two or three sentences on who you are and what kind of role you're
after. Markdown is allowed here.
experiences:
- company: Some Company
year: May 2021 - Jun 2024
position: Data Engineer
description: >-
- **Achievement** with a measurable outcome.
- Another bullet describing impact, tools, scale.
education:
- name: Some University
location: City, Country
year: 2015 - 2020
diplomaName: MSc, Computer Science
projects:
- name: Side Project
year: Since 2026
description: >
One line on the project and the stack used.A complete, real-world example lives at
examples/cv.yaml.
The cover-letter-template.md file
Only needed for tailor_cv_and_letter. There's no download for this one —
write your own. It's a normal Markdown letter where the parts that should be
rewritten per offer are wrapped in [[TAILOR: instructions]]example text[[/TAILOR]]
markers: the instruction tells the model what to write, and the example text shows
the tone/length to match. Everything outside the markers is kept verbatim.
# Subject: Application for [[TAILOR: the job title from the offer]]Data Engineer[[/TAILOR]] Position
Dear Hiring Team,
I am a Data & Software Engineer with five years of experience [...].
[[TAILOR: one sentence speaking directly to THIS company, its scale, mission, or
specific challenges; mirror the tone of this paragraph]]Example sentence about the
company.[[/TAILOR]]
[[TAILOR: a paragraph covering a first angle relevant to the offer (data pipelines,
APIs, cloud). Be specific: name companies, tools, outcomes from the adapted YAML.
Keep the same length and register as this example]]Example paragraph.[[/TAILOR]]
[...]
Best regards,
Jane Doe
jane.doe@example.comA complete example lives at
examples/cover-letter-template.md.
Development
This project uses uv.
uv sync --dev # install deps
uv run playwright install chromium # one-time: browser for rendering/tests
uv run ruff format . # format
uv run ruff check . # lint
uv run pytest # testsThe test suite renders the live default CV from notboringresume.cloud, so it needs network access and will fail if the site is down.
Continuous integration
CI (lint + tests) runs on every pull request and push to main. See
.github/workflows/ci.yml for details.
Releasing (publishing to PyPI)
Releases are on-demand and automated with
python-semantic-release —
trigger the release workflow manually with gh workflow run release.yml --ref main
and it bumps the version, tags, and publishes to PyPI from the
Conventional Commit history. See
.github/workflows/release.yml for the full flow.
Available Tools
4 toolsfetch_offerA
Fetch a job offer from a URL and return its visible text.
Use this when the user gives a link instead of pasting the offer. The page is rendered in a headless browser, so it works on JavaScript-heavy job boards.
Args: url: the job offer URL.
| Name | Required | Description | Default |
|---|---|---|---|
| url | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Discloses headless browser rendering, which is useful. However, with no annotations, more details about output format or potential limitations would improve transparency.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Concise and well-structured: purpose first, then usage, then technical note, then parameter. Every sentence is essential.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Covers main aspects: purpose, usage context, technical details. With an output schema present, the description is sufficiently complete for a simple fetch tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Only one parameter (url) described as 'the job offer URL', which adds minimal value over the schema's type string. With 0% schema coverage, the description should elaborate on expected format or examples.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Clearly states the action 'Fetch a job offer' from a URL, returning visible text. Distinct from sibling tools like generate_letter_pdf and load_cv.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly says 'Use this when the user gives a link instead of pasting the offer', providing clear context. Also notes it works on JavaScript-heavy job boards, aiding selection.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
generate_letter_pdfA
Render a cover letter written in Markdown into a clean, classic A4 PDF.
Provide the letter either inline via text, or as an existing Markdown file via
letter_path — so the PDF can be produced from a letter that already exists,
without composing a new one. Uses the same local Chromium as the CV, so it works
on any machine without Word or extra system dependencies. Returns {"path"}.
Args:
text: the cover letter in Markdown. Blank lines separate paragraphs; a
top-level heading (# Subject: ...) is styled as the light-blue header.
letter_path: path to an existing Markdown letter to render instead of text.
output_path: where to save the PDF, e.g. output/Acme/backend-dev/cover-letter.pdf.
| Name | Required | Description | Default |
|---|---|---|---|
| text | No | ||
| letter_path | No | ||
| output_path | No | cover-letter.pdf |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Discloses use of local Chromium and return of path, but does not mention if files are overwritten, error behavior, or permissions. With no annotations, the description carries the burden and is adequate but not comprehensive.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is structured with separate sentences and an Args section. It is informative but could be shortened slightly; however, it effectively communicates key details without significant waste.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Covers input modes, output format, and dependency (Chromium). No output schema, so the return value is explained. Missing error handling and file overwriting behavior, but for a focused tool, it is fairly complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema has 0% description coverage, but the description compensates by explaining each parameter: text (Markdown structure), letter_path (alternative input), output_path (save location). Adds meaningful context beyond the parameter names.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Clearly states it renders a cover letter in Markdown to an A4 PDF, identifying the specific resource (cover letter) and output format. The sibling generate_pdf is more generic, so this tool's focus on cover letters distinguishes it well.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides guidance on when to use text vs letter_path, and mentions it works without Word. However, it does not explicitly compare to the sibling generate_pdf, which could cause confusion about which to use for general PDF generation.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
generate_pdfA
Render a YAML CV into a one-page PDF via notboringresume.cloud.
Writes the PDF to output_path and returns {"path", "overflows"}.
If "overflows" is True, shorten the YAML and call this tool again.
Args:
yaml: the CV content in YAML (already tailored to the job offer). Omit it to
render the site's built-in default CV (handy for a quick manual test).
output_path: where to save the PDF, e.g. output/Acme/backend-dev/cv.pdf.
Defaults to cv.pdf in the current directory.
cv_path: path to the original CV YAML. When given, the photo from that file is
reattached to yaml before rendering (it was stripped by load_cv).
| Name | Required | Description | Default |
|---|---|---|---|
| yaml | No | ||
| cv_path | No | ||
| output_path | No | cv.pdf |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations exist, so the description bears full responsibility. It discloses the external dependency (notboringresume.cloud), the output behavior (writes to output_path, returns {path, overflows}), the overflow handling pattern, and the photo reattachment logic. However, it does not mention authentication requirements or error behavior if the external service fails.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured: a one-line purpose, output note, overflow guidance, then a clear 'Args:' list. Every sentence adds value; no redundancy. It is appropriately sized and front-loaded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool has no output schema and no annotations, the description provides adequate context: explains the transformation, the parameters, the external service dependency, and the overflow retry logic. It does not require additional detail for typical use.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, yet the description fully explains all three parameters via an 'Args:' section. It provides purpose, defaults, and usage context for each (e.g., yaml′s role in tailoring, cv_path′s photo reattachment, output_path′s default). This fully compensates for the schema gap.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The first sentence clearly states the action: 'Render a YAML CV into a one-page PDF via notboringresume.cloud.' This specifies the verb (render), resource (YAML CV), and output (one-page PDF). It distinguishes from siblings like load_cv (which loads CV data) and generate_letter_pdf (letter PDF).
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides internal usage tips (e.g., handle overflow by shortening YAML and retrying, omit yaml for a quick test) but does not explicitly differentiate from sibling generate_letter_pdf or state when to use this tool over others. The guidance is partially present but lacks cross-tool context.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
load_cvA
Return the CV YAML with its embedded photo removed.
Read the CV through this tool instead of opening the file directly: the photo is a base64 data URI that is huge and useless for tailoring. Work from the returned text; the photo is reattached automatically by generate_pdf.
Args: cv_path: path to the CV YAML.
| Name | Required | Description | Default |
|---|---|---|---|
| cv_path | No | ./cv.yaml |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description explains the key behavior: the photo is removed from the returned text and reattached later. It implies a safe read operation without side effects, though it does not explicitly state non-destructiveness.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three concise sentences plus a one-line Args section. Every sentence adds value: purpose, rationale, usage guidance, and parameter definition. No wasted words.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema available, the description does not need to detail return format. It adequately explains the transformation (photo removal) and usage context. Could mention that the output is YAML text, but the title implies it.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The single parameter cv_path has a minimal description ('path to the CV YAML') that adds little beyond the property name. Given 0% schema description coverage, more detail would be beneficial, though the default value is noted in schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states it returns the CV YAML with the photo removed, a specific verb-resource pair. It distinguishes from siblings (fetch_offer, generate_pdf) by focusing on loading CV data only.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly tells when to use this tool (instead of opening the file directly) and why (photo is huge and useless). Also notes that the photo is reattached by generate_pdf, providing context for downstream usage.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
4 tool updates
v0.1.0- First observed
fetch_offer - First observed
generate_letter_pdf - First observed
generate_pdf - First observed
load_cv
TDQS
Scored across 4 tools
Each tool has a clearly distinct purpose: fetching a job offer, generating a cover letter PDF, generating a CV PDF, and loading CV YAML. No overlap or ambiguity.
All tool names follow a consistent verb_noun pattern (fetch_offer, generate_letter_pdf, generate_pdf, load_cv), using snake_case and clear action verbs.
With 4 tools, the server is well-scoped for its purpose (resume/CV generation). Each tool covers a essential step in the workflow without unnecessary extras.
The tool surface covers the key workflow (fetch offer, load CV, generate CV and letter), but lacks explicit editing or versioning tools. Minor gap, but core functionality is present.
Maintenance
Related MCP Connectors
Generate tailored, ATS-optimized resume PDFs and cover letters from a job description, over MCP.
Build, version and render resumes as PDFs from Claude or any MCP client.
Validate, build, and publish the resume you keep as YAML in your own GitHub repository.
Tailor resumes, generate cover letters, render CVs as PDF, and browse 22+ templates.
Related MCP Servers
- FlicenseNot gradedqualityCmaintenanceEnables AI assistants to fetch a master resume, tailor it to a job description, and generate a polished PDF resume using headless Chromium.-
- AlicenseAqualityAmaintenanceTailor your CV to any job posting with ATS keyword scoring and clean PDF/DOCX export.63MIT
- AlicenseAqualityBmaintenanceTailors LaTeX résumés, CVs, and cover letters to job descriptions by injecting truthfully-selected content from a master CV, compiling PDFs, and logging applications.111MIT
- AlicenseNot gradedqualityCmaintenanceEnables users to tailor a one-page LaTeX CV to a job posting by fetching relevant facts from a YAML file, rendering a LaTeX document from id-based selections, and compiling it to PDF, without wasting tokens on repetitive CV reads or compiler logs.MIT