Skip to main content
Glama
maxim-kich

cv-builder

by maxim-kich

Slop-Disclaimer

It's a vibe coded experiment that helped me personally building my CVs as I want instead of paying 30$ for some lame subscription. You can self host it locally or on VPS and connect your agent to it, both REST or MCP supported.

Use it as you wish. There is no contribution expected. And of course this readme was not meant to be read by humans, let your agent read and explain it for you.

CV Builder

A self-hosted CV editor, PDF renderer, REST API, and Model Context Protocol (MCP) server. CVs are stored by the server, so the browser UI and multiple AI agents work on the same documents.

Related MCP server: cv-forge-mcp

What is exposed

  • Web editor: /

  • REST API: /api/v1

  • OpenAPI description: /api/v1/openapi.json

  • Streamable HTTP MCP: /mcp

  • Health check: /api/v1/health

  • MCP tools: list_cvs, get_cv, create_cv, update_cv, delete_cv, and export_cv

  • OAuth protected-resource discovery: /.well-known/oauth-protected-resource/mcp

PDFs are rendered on the server. export_cv returns an MCP PDF resource, while GET /api/v1/cvs/{id}/pdf returns a normal downloadable file.

PDF page count is content-driven rather than fixed by the template. A short CV can render as one A4 page, while longer content automatically flows to three or more pages. The bundled example's two-page check is only a visual-layout regression for that specific fixture.

Run locally

Requirements: Node.js 22 or newer and npm.

npm install
npm run dev

Open http://127.0.0.1:5173. Development uses a durable SQLite database at data/cv-builder.sqlite and starts with an empty workspace. Set a token before exposing the process to any network:

CV_BUILDER_API_TOKEN="$(openssl rand -hex 32)" npm run dev

The macOS start.command and generated Dock launcher still work. The server owns the data now; browser localStorage is not used as a database.

To load the fictional example into a new database, set CV_BUILDER_SEED_FILE=examples/sample-cv.md on the first start.

Run with Docker

Create local secrets once:

cp .env.example .env
openssl rand -hex 32

Paste the generated value into CV_BUILDER_API_TOKEN in .env, then start the SQLite version:

docker compose up -d --build

The application is available at http://localhost:5173. SQLite is stored in the named cv_builder_data volume and uses WAL mode. Back up that volume or the database file.

For PostgreSQL, also set a different POSTGRES_PASSWORD and run:

docker compose -f compose.yaml -f compose.postgres.yaml up -d --build

PostgreSQL is recommended when the service will have multiple replicas, external backups, or several active users. The schema is initialized automatically.

Deploy with Coolify

Use compose.coolify.yaml as a self-contained CV Builder and PostgreSQL stack. It intentionally has no Caddy service and no host port mappings: Coolify supplies the private network, reverse proxy, domain routing, and HTTPS.

  1. Create a Coolify resource from this GitHub repository.

  2. Select the Docker Compose build pack, use / as the base directory, and set the Compose location to /compose.coolify.yaml.

  3. Add the runtime variables documented in docs/mobile-plugin-deployment.md. The complete set for ChatGPT mobile is:

    CV_BUILDER_API_TOKEN=<output of: openssl rand -hex 32>
    POSTGRES_PASSWORD=<different output of: openssl rand -hex 32>
    CV_BUILDER_PUBLIC_URL=https://cv.example.com
    CV_BUILDER_OAUTH_ISSUER=https://YOUR_AUTH0_DOMAIN/
    CV_BUILDER_OAUTH_AUDIENCE=https://cv.example.com/mcp
    CV_BUILDER_OAUTH_JWKS_URL=https://YOUR_AUTH0_DOMAIN/.well-known/jwks.json
    CV_BUILDER_OAUTH_ALLOWED_SUBJECTS=auth0|OWNER_USER_ID

    For a staged rollout, the OAuth variables may remain empty during the first deployment. Existing browser and static-token access continues working, but ChatGPT mobile remains unavailable until all OAuth variables are configured together and the service is redeployed.

  4. Assign https://cv.example.com:8080 to the cv-builder service. The :8080 suffix tells Coolify which internal container port to proxy; the public URL still uses normal HTTPS.

  5. Deploy, then open /api/v1/health and confirm that storage is postgres and authentication is required.

The Compose stack limits the app to 512 MB RAM and PostgreSQL to 1 GB. Those are safety ceilings, not expected steady usage. The Node and PostgreSQL images support both AMD64 and ARM64 hosts.

The authentication and storage model is one private workspace per deployment. For Maxim and Valeriia, deploy this repository twice with distinct domains, OAuth audiences/subjects, access tokens, PostgreSQL passwords, and stack volumes. Follow the linked backup, Auth0, installation, test, recovery, and rollback runbook before enabling mobile access.

Put it on a VPS with HTTPS

Point a DNS A/AAAA record at the VPS, set CV_BUILDER_DOMAIN in .env, and start the PostgreSQL and Caddy overlays:

docker compose \
  -f compose.yaml \
  -f compose.postgres.yaml \
  -f compose.remote.yaml \
  up -d --build

Caddy obtains and renews TLS certificates. Only ports 80 and 443 need to be public; the direct app port is bound to 127.0.0.1. The agent endpoint is then https://YOUR_DOMAIN/mcp.

Keep .env off the server's public filesystem, restrict SSH access, and arrange automated PostgreSQL backups before treating the service as the only copy of a CV.

Connect agents

Every agent belonging to one workspace uses that deployment's MCP URL and bearer token. REST-only agents can use the API instead. Agents for another person should use that person's separate deployment and token.

Local Codex and legacy desktop agents

Export the token in the environment that launches Codex/ChatGPT:

export CV_BUILDER_TOKEN="the-value-from-CV_BUILDER_API_TOKEN"

Add this to ~/.codex/config.toml (or project-local .codex/config.toml):

[mcp_servers.cv_builder]
url = "https://YOUR_DOMAIN/mcp"
bearer_token_env_var = "CV_BUILDER_TOKEN"

Codex CLI/IDE and compatible local desktop agents can keep using this migration path. Restart the client after adding it. Hosted ChatGPT plugins should use OAuth instead.

ChatGPT web, Desktop, iOS, and Android

Use the hosted OAuth connection and private plugin package described in docs/mobile-plugin-deployment.md. ChatGPT authenticates in a browser with Authorization Code + PKCE and then calls the hosted /mcp URL directly; no Mac or manually copied API token is involved after installation.

Hermes, Claude, and other MCP clients

Add a Streamable HTTP MCP server with:

  • URL: https://YOUR_DOMAIN/mcp

  • Header: Authorization: Bearer YOUR_TOKEN

Hermes supports the hosted OAuth path directly:

hermes mcp add --url https://YOUR_DOMAIN/mcp --auth oauth cv-builder
hermes mcp test cv-builder

The built-in static token remains intended for personal desktop/server-side agents and browser login, not ChatGPT mobile.

Agent workflow

A reliable CV-preparation run looks like this:

  1. Call list_cvs and choose a source CV.

  2. Call get_cv and keep its revision.

  3. Tailor the structured resume fields or generated Markdown for the requested role.

  4. Call create_cv for a new named variant, or update_cv with expectedRevision.

  5. Call export_cv with format: "pdf" and return the PDF resource to the user.

Revision checks prevent one agent from silently overwriting another agent's edit.

REST API example

export CV_URL="https://YOUR_DOMAIN"
export CV_TOKEN="the-value-from-CV_BUILDER_API_TOKEN"

curl -fsS "$CV_URL/api/v1/cvs" \
  -H "Authorization: Bearer $CV_TOKEN"

curl -fsS "$CV_URL/api/v1/cvs" \
  -H "Authorization: Bearer $CV_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"title":"Product Designer — Acme","markdown":"# Candidate Name\n\n## Product Designer\n\n..."}'

curl -fsS "$CV_URL/api/v1/cvs/CV_ID/pdf" \
  -H "Authorization: Bearer $CV_TOKEN" \
  -o tailored-cv.pdf

The complete machine-readable operation list is at /api/v1/openapi.json.

Configuration

Variable

Default

Purpose

CV_BUILDER_API_TOKEN

unset

Protects the UI session, REST API, and MCP endpoint. Required for remote use; minimum 6 characters. A long random token remains strongly recommended.

CV_BUILDER_OAUTH_ISSUER

unset

Exact trusted authorization-server issuer.

CV_BUILDER_OAUTH_AUDIENCE

<public URL>/mcp

Exact resource/audience required in OAuth access tokens.

CV_BUILDER_OAUTH_JWKS_URL

unset

HTTPS JWKS used to verify OAuth JWT signatures.

CV_BUILDER_OAUTH_ALLOWED_SUBJECTS

unset

Comma-separated immutable OAuth sub values allowed in this deployment. Use one owner in production.

CV_BUILDER_OAUTH_ALGORITHMS

RS256

Comma-separated JWT signature algorithm allowlist.

CV_BUILDER_OAUTH_MAX_TOKEN_LIFETIME_SECONDS

600

Reject OAuth tokens whose exp - iat exceeds this short-lived-token ceiling.

CV_BUILDER_OAUTH_REVOKED_TOKEN_IDS

unset

Emergency comma-separated JWT jti denylist.

CV_BUILDER_OAUTH_REVOKED_BEFORE

unset

Emergency Unix timestamp invalidating tokens issued at or before it.

CV_BUILDER_OAUTH_INTROSPECTION_*

unset

Optional RFC 7662 endpoint and server-side credentials; configure all three together.

DATABASE_URL

sqlite:./data/cv-builder.sqlite

SQLite path or PostgreSQL connection URL.

CV_BUILDER_PUBLIC_URL

local server URL

Canonical HTTPS origin used in MCP download links.

CV_BUILDER_SEED_FILE

unset

Optional initial Markdown document used only when the database is empty.

HOST

127.0.0.1 locally, 0.0.0.0 in production

Listen address.

PORT / CV_BUILDER_PORT

5173

Listen port.

CV_BUILDER_ALLOW_QUIT

enabled in development

Allows the local macOS launcher to stop the process.

Source Markdown format

The optional Markdown input keeps the existing hierarchy:

  • # candidate name

  • the first ## professional title

  • contact lines with mailto: and tel: links

  • ## Profile, ## Employment History, ## Education, ## Skills, and ## Languages

  • ### for each employment or education entry

  • a bold date line followed by | and its location for employment entries

  • language values in Language: value/maximum form

Structured fields remain the source of truth after parsing.

The repository includes examples/sample-cv.md, which uses fictional identity and employment data. Personal source files, local databases, generated PDFs, .env, and local Codex hooks are excluded from Git and the Docker build context.

Build and verify

npm test
npm run build
npm run verify:pdf

Tests cover OAuth discovery; signature, issuer, audience, expiry, subject, revocation, and scope enforcement; authenticated sessions; CRUD and revision conflicts; every CV MCP tool; server and MCP PDF export; a real Streamable HTTP MCP handshake; PDF geometry, text, links, and content-driven pagination in both directions.

License

CV Builder is available under the MIT License. The bundled Arimo document fonts and JetBrains Mono interface fonts remain under the SIL Open Font License 1.1; their respective copyright and license texts are included in public/fonts/ARIMO-OFL.txt and public/fonts/JETBRAINS-MONO-OFL.txt.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

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

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    D
    maintenance
    An MCP server for managing career experience data using the JSON Resume schema with custom extensions. It enables AI agents to store, update, and retrieve detailed work history, projects, and achievements to facilitate tailored resume generation.
  • A
    license
    Not graded
    quality
    D
    maintenance
    Exposes a personalized AI agent that reads your resume and provides intelligent responses about your professional background through a standardized MCP server interface with RAG capabilities.
    MIT

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/maxim-kich/cv-builder'

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