cv-rest-mcp-server
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., "@cv-rest-mcp-servergenerate my CV as a PDF using the modern theme"
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.
CV REST/MCP Server
FastAPI + FastMCP service rendering a CV as JSON, HTML, themed PDFs, and MCP tools. Operator login guards mutating/authed endpoints; the same JD you're applying to can be tailored against your skill bank and checked for gaps. See docs/using-gap-analysis.md for the "what should I learn next?" workflow.
Architecture
Two services, one codebase:
Service | Role | Deployed as |
API | FastAPI + FastMCP; renders CV; validates operators |
|
SPA | React 19 + Vite; operator login & dashboard |
|
Locally: Both run in dev mode (API on 8080, SPA on 5173). just dev-local starts the API with hot reload; just dev-spa starts the SPA (separate terminal).
Cloud Run: Separate services. SPA nginx serves static assets (Vite-hashed); API is JSON-only. A reverse proxy (or CDN) routes /app.domain → SPA and /api.domain → API.
Related MCP server: cvx
Authentication
Operators sign in at /login (served by the SPA) with username/password. API issues an HS256 JWT access token plus a refresh token; both are Postgres-backed (DATABASE_URL, required, no default — see CLAUDE.md).
Unauthenticated requests:
GET /,GET /health— allowedGET /cv,/cv/html,/cv/preview,/cv/pdf(live CV, notailoredselector) — allowedEverything under
/api/v1/*, plus a?tailored=selector on the public CV routes — JWT required
See CLAUDE.md for env vars (JWT_SIGNING_KEY, FIRST_ADMIN_USERNAME, etc.).
Getting Started
Just want to see the CV locally?
just setup && just dev-localOpen http://localhost:8080. just dev-spa (separate terminal) starts the operator SPA on 5173 for login and the tailoring/gap-analysis UI.
Want to modify the CV data?
Edit data/cv.json (validated against CVData in services/portfolio/cv_data.py). Restart the API server.
Set CV_DATA_PATH env var to point to a different JSON file. See data/cv.example.json for the full schema.
Want to try job-description gap analysis?
See docs/using-gap-analysis.md.
Ready to deploy to GCP?
See Deployment below.
API
REST Endpoints
Public (no auth):
Method | Path | Description |
GET |
| Landing page |
GET |
| Health check |
GET |
| Live CV as JSON |
GET |
| Live CV rendered as HTML |
GET |
| Preview page with toolbar |
GET |
| Live CV as PDF (attachment) |
Operator-only (JWT required — cv:read / cv:manage scopes, see AGENTS.md):
Method | Path | Description |
GET |
| Operator CV as JSON (supports tailored revisions) |
GET |
| Operator CV as PDF |
POST |
| Tailor the CV against a job description |
GET |
| List saved tailored revisions |
POST |
| Store a job posting |
GET |
| List stored postings |
POST |
| Run gap analysis on a posting |
GET |
| Read a stored gap report |
GET |
| Ranked "what to learn next" roadmap |
* |
| CRUD for ATS boards under continuous monitoring |
* |
| CRUD for operator documents (CV / skill bank / JD vocabulary) |
See docs/using-gap-analysis.md for how the gap-analysis endpoints fit together, and docs/api.md for the full contract.
Interactive OpenAPI docs (Swagger UI): /docs
MCP Tools
Mounted at /mcp via HTTP JSON-RPC transport. Any MCP client (Claude Desktop, Cursor, VS Code, Windsurf) can connect:
{
"mcpServers": {
"cv-rest-mcp-server": {
"url": "http://localhost:8080/mcp"
}
}
}For deployed: replace http://localhost:8080 with your public API URL.
Available tools:
Tool | Parameters | Returns |
| — | JSON object with full CV data |
| — |
|
|
| Base64-encoded PDF bytes |
|
| Tailored CV JSON matched against a posting |
Themes
Four built-in themes: classic, minimal, modern, original. Defined in services/portfolio/themes/<name>.py as CSS strings.
Add a new theme: create services/portfolio/themes/yourname.py with a CSS constant.
Rate Limiting
Per-IP (X-Forwarded-For-aware behind a trusted proxy), in-memory. Loopback peers exempt in local dev. Every limited endpoint stacks a per-minute burst cap with a per-hour sustained cap; a sample:
Endpoint | Limit |
| 30/min, 120/hour |
| 60/min |
| 30/min, 600/hour |
| 30/min, 300/hour |
| 5/15min, 15/hour |
| 10/min, 60/hour |
Development
All commands use uv for dependency management:
uv sync --group dev # Install dependencies (first time)
uv run pytest # Run tests (522 total)
uv run pytest -x # Stop on first failure
just code-quality # Ruff + type check
just dev-local # Start the API with hot reload
just dev-spa # Start the SPA (separate terminal)
npm run css # Rebuild Tailwind (after template changes)See CLAUDE.md for full command reference.
Docker
Build and run both services locally in a container:
just build && just runOr build images manually for a GCP project:
just build-images <your-gcp-project>This builds api-core, spa-origin, and any other service images and pushes them
to the cv-images Artifact Registry repo
(<region>-docker.pkg.dev/<project>/cv-images/<service>).
Deployment
New to DNS, load balancers, or Terraform? docs/infrastructure.md explains how a browser request reaches your code — DNS delegation, SSL certificates, the load balancer, Cloud Run, and how Terraform ties them together — using this project's real resources.
Local Development
just dev-local # API, port 8080
just dev-spa # SPA, port 5173 (separate terminal)Both start with hot reload. No setup required beyond just setup.
Cloud Run (GCP)
One-time bootstrap (idempotent):
export GCP_PROJECT=<your-gcp-project>
just deploy bootstrap # Enable APIs, create CV bucket, set IAM
just deploy bootstrap-state # Create Terraform state bucket
just deploy bootstrap-secrets # Create JWT signing key + refresh token pepper
cd terraform && terraform plan && terraform apply # Deploy all services
just deploy upload-cv # Upload your CV data to GCSSee CLAUDE.md for the full step-by-step with configuration details.
Cost Estimation (Infracost)
Before deploying, estimate monthly GCP costs:
# Local estimate (requires Infracost CLI installed)
infracost breakdown --path terraform/
# Set up CI/CD cost estimates on PRs (requires INFRACOST_API_KEY secret)
# See CLAUDE.md#cost-estimation for detailsBudget: $100/month. Pre-commit hook and CI/CD automatically warn if costs trend high.
Subsequent releases:
Two path-filtered workflows split infrastructure from application releases —
Terraform owns the platform, gcloud run deploy ships the code:
You changed | Workflow | What runs |
|
| lint + tests → build images to Artifact Registry → |
|
| tflint + checkov → Infracost → |
An app-only commit never runs Terraform, and an infra-only commit never rebuilds
images. Use [skip deploy] in a commit message to run checks without deploying.
Infra applies are gated on the production GitHub Environment: terraform plan posts its
output to the PR, and the apply job waits for a required reviewer before running
the exact reviewed plan. Application rollbacks don't need Terraform — redeploy a
previously built image tag.
The deployed URL is printed by the verify job and visible in Google Cloud Console under Cloud Run.
Testing
uv run pytest # Full suite (522 tests)
uv run pytest services/portfolio/tests/test_auth.py -xvs # Auth tests with verbose output
uv run pytest --cov # Coverage report (96% target)Tests run against a real, ephemeral Postgres via testcontainers (Docker required). See CLAUDE.md for auth fixture details.
Stack
Backend: FastAPI, FastMCP v3, SQLAlchemy (asyncpg/psycopg), Alembic, WeasyPrint, Jinja2
Frontend: React 19, TypeScript, Vite, TanStack Query (React Query), Tailwind CSS
Database: Cloud SQL Postgres (Auth Proxy), Alembic-migrated
Deployment: Cloud Run, Terraform, GitHub Actions CI/CD
Design: Stateless, $PORT-aware, 12-factor config (env vars)
Project Status
Phase 2: Postgres-backed users, revisions, and gap analysis; JD tailoring against a skill bank; continuous ATS-board monitoring feeding a ranked learning roadmap. 522 tests passing. See CLAUDE.md for key files and non-obvious patterns.
For questions or contributions, see AGENTS.md (detailed setup and troubleshooting) or CLAUDE.md (internal patterns and commands).
This server cannot be deployed
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.
Public portfolio MCP for resume, services, availability, project evidence, and introductions.
Resume builder with native MCP — create and edit resumes from your AI assistant.
Related MCP Servers
- FlicenseAqualityDmaintenanceEnables resume parsing, querying, and email notifications via MCP tools.31-
- AlicenseNot gradedqualityAmaintenanceMCP server for CVX, enabling AI assistants to create, validate, and build professional CV PDFs from YAML content, with tools for schema retrieval, project initialization, validation, and rendering.386 npm2Apache 2.0
- FlicenseNot gradedqualityBmaintenanceProvides MCP tools for managing a CV as structured content, including a SQLite-backed snippet library with tools to list, create, update, and match job postings, compose role-tailored CV variants, and manage drafts.-
- FlicenseNot gradedqualityCmaintenanceEnables AI assistants to query a person's CV and portfolio content via MCP tools and resources, returning grounded answers from local markdown data instead of relying on resume parsing.-