Skip to main content
Glama
Zetetic-Dhruv

job-search-mcp

README.md
# job-search-mcp

Infrastructure for running a **job search with Claude Code**. Point it at a folder with your CV +
a small config; it discovers roles, fetches each company's **exact** application fields, drafts
**non-trivial** applications (positioning, not just autofill), and renders a **navigable, offline
dashboard** with one-click copy for every field. Nothing is auto-submitted — you review and send.

Works two ways: as a set of **Claude Code skills + an MCP server** (talk to Claude), or as a **CLI**.

---

## What it does

| Step | Module | Output |
|---|---|---|
| CV → structured profile JSON | `parse_cv.py` | `<data>/profile.json` |
| Discover roles (LinkedIn/Indeed/Naukri/Google) | `scrape_jobs.py` | `<data>/output/jobs.json` |
| Fetch a job's **exact** required fields | `ats.py` | Greenhouse + Ashby = full; Lever/Workday = standard |
| Fill an application against those fields | `generate_application.py` | `<data>/applications/*.json` |
| Make it **non-trivial** (reframe + product teardown + proof-map) | `nontrivial.py` | a `nontrivial` block per application |
| Render everything to one offline page | `build_dashboard.py` | `<data>/dashboard.html` |

**Design principle — human-in-the-loop.** It prepares applications; you submit them. Fully-automated
apply bots violate LinkedIn policy (permanent-ban risk) and are out of scope by design.

## Your data folder

You keep your inputs and outputs in one folder, separate from this repo. Point the tool at it with
`--data-dir` or the `JOBSEARCH_DATA` env var.

```
my-jobsearch/
  profile.json          # from parse-cv, or copy examples/profile.example.json
  config.json           # optional; copy examples/config.example.json
  companies.json        # optional; a curated target list (Claude can research one)
  nontrivial_kits.json  # optional; pre-authored per-company kits
  output/jobs.json      # written by the tool
  applications/*.json   # written by the tool
  dashboard.html        # written by the tool
```

## Setup

```bash
python3 -m venv .venv && source .venv/bin/activate   # Python 3.10+
pip install -r requirements.txt
export ANTHROPIC_API_KEY=…        # optional: LLM CV-parsing + auto-drafted non-trivial kits
```

## Use it — CLI

```bash
D=~/my-jobsearch
python -m src.cli --data-dir $D parse-cv --cv ~/MyCV.pdf     # CV -> profile.json
python -m src.cli --data-dir $D scrape                       # -> output/jobs.json
python -m src.cli --data-dir $D apply --url "<job_url>"      # -> applications/<company>.json (+ non-trivial kit)
python -m src.cli --data-dir $D dashboard                    # -> dashboard.html
open $D/dashboard.html                                       # or: python -m http.server -d $D
```

## Use it — Claude Code (MCP + skills)

1. Add the MCP server (see `.mcp.json`) and set `JOBSEARCH_DATA` to your folder.
2. In a Claude Code session in this repo, just ask: *"find jobs"*, *"apply to <link>"*,
   *"make this application non-trivial"*, *"build my dashboard"*. The skills in `.claude/skills/`
   drive the backend; the MCP server (`src/mcp_server.py`) exposes the same as callable tools
   (`get_profile`, `read_jobs`, `refresh_jobs`, `get_application_fields`, `generate_application`,
   `make_nontrivial`, `score_triviality`, `build_dashboard`, `list_companies`).

## What "non-trivial" means

A *trivial* application restates your CV in the form's fields — the axis an ATS reduces to keywords.
A *non-trivial* one changes what the reader thinks they're hiring for: it **reframes** the role onto
an axis where you win, carries a **witness only you could produce** (a short teardown of *their*
product through your lens), and **maps every claim to a real fact in your CV** (the honesty gate —
unbacked claims are flagged, never invented). See `src/nontrivial.py` and the `make-nontrivial` skill.

## Tests

```bash
python -m tests.adversarial          # offline
python -m tests.adversarial --net    # + live ATS probes
```

## Honest caveats

- **Scraping ToS:** Naukri/LinkedIn/Indeed prohibit automated scraping. For personal, low-volume use
  the practical risk is IP rate-limiting, not litigation — run modestly and pair with each board's own
  saved-search alerts. If a board returns nothing, it's likely a temporary block.
- **Fetch failures are surfaced, never hidden.** If a company's real form can't be loaded, the template
  is flagged `fetch_failed` and the dashboard shows a red banner — verify on the apply page.
- **Salary/notice/relocation** are marked `TODO_CONFIRM` and surfaced for review; the tool never guesses them.