# freehire [Health: Active]

**Category:** 🏢 Workplace & Productivity  
**Repository:** https://github.com/strelov1/freehire-mcp  
**GitHub Stars:** 12  
**npm Downloads (last month):** 274  
**Views:** 5  
**Installs:** 0  
**Upvotes:** 0  
**Directory Page:** https://allmcps.com/mcp/freehire

## Description
freehire.me: search 3.3M+ IT jobs from 294K company boards, track applications, tailor CVs.

## Tools
Capabilities this server exposes over MCP:

- **whoami** — Return the authenticated freehire user (verifies the API key). Call this to confirm auth before other tools.
- **facets** — List the market's filter vocabulary: every facet's live values with a vacancy count each, plus the skills list and numeric ranges. Call this FIRST to discover real values for `search` and `market_fit` — do not invent facet values. A filter key the API does not recognise is ignored rather than refused, so a result wrapped as {data, ignored} counted a broader market than the one asked for — retry with the suggested name before quoting any number from it.
- **search** — Search open jobs by keyword with optional facet filters. Each result carries the job's FULL description as markdown alongside title, company, location and public_slug, plus the total match count — so you can screen a whole result set without calling `job` per hit. Use the returned slug with `job`, `apply`, `save`, etc. Two traps worth knowing. Geography (region/country/city) is ONE OR-group: passing region AND country widens rather than narrows, so drop the region to search a single country. And a filter param the API does not recognize is ignored rather than refused — the search still runs, just broader — so when a result carries an `ignored` list, its `total` answers a wider question than the one asked; retry with the suggested name before reporting the number.
- **market_fit** — Score a skill list against the live open-vacancy market for a filtered role: headline coverage (% of vacancies listing ≥1 skill), must-have skills held, and the missing skills that unlock the most vacancies. Here `skills` is the MEASURED set, not a filter — use facet params to define the role. One skill probes that skill's demand.
- **job** — Fetch a single job's full content by slug (title, company, location, posting URL, description).
- **company** — Fetch a company and its open jobs by company slug.
- **apply** — Mark a job as applied for the authenticated user. Idempotent.
- **save** — Bookmark a job for later. Idempotent.
- **unsave** — Remove a job's bookmark. A no-op if it was not saved.
- **stage** — Set a job's application stage. The server validates the value; valid stages are applied/screening/responded/interview/offer/accepted/rejected/withdrawn.
- **note** — Attach a free-text note to a tracked job (overwrites the existing note).
- **my** — List the caller's tracked jobs (viewed/saved/applied) with their stage and note. Filter narrows the set.
- **cv_list** — List the caller's tailored CVs, newest edit first, each with the vacancy it was written for. Use this to find the id the other cv_* tools take, or to check whether a vacancy already has a tailored copy.
- **cv_tailor** — Start tailoring a CV to a vacancy, returning the tailored CV's id (plus the base it was copied from and the bound session). Idempotent per vacancy — calling it again for the same slug reopens the copy that already exists, so it is safe when you do not know whether one exists. It spends one of the candidate's AI credits the first time it creates the copy (402 when the balance will not cover it) and 409s when they have no résumé on the site to seed a base CV from — tell them to upload one; you cannot. It does not call a model: the reframing is your work, through cv_context and cv_edit.
- **cv_context** — Show the cached fit-analysis context a tailored CV should reframe toward: verdict, recommendation, dimension comments, and the requirement split — missing_have (reframe existing evidence) vs missing_gap (ask the candidate before adding). Read this before editing.
- **cv_get** — Fetch a tailored CV with its full document (header, summary, experience bullets, skill groups).
- **cv_edit** — Apply a batch of path-addressed edits to a tailored CV, atomically. Read cv_context and cv_get first — indices are counted over the document cv_get returned. THE HONEST WALL: editing with an API key edits as the tailoring agent, and the server enforces it — the candidate's own name, email, phone and links are refused, and anything stating what they DID needs evidence_id, the id of something they asserted themselves. One uncited op rejects the whole batch. For a missing_have requirement, reframe an existing bullet; for a missing_gap, ask the candidate before writing anything. A bad path is a 422 and the CV is untouched. Export with cv_render.
- **cv_render** — Render a tailored CV to an ATS PDF, returned as a base64 resource (application/pdf). The bytes are large and not human-readable to the model — call it to produce the deliverable, not to inspect content.
- **experience_list** — Read the candidate's whole experience bank: every employment and the achievements attached to it, plus the ones attached to no place under `unplaced`. Each achievement carries a PROVENANCE — cv_import, stated_in_chat and manual mean the candidate asserted it and it may be cited on a CV; agent_inferred means a model read it into the record and it may NOT. Take evidence_id for cv_edit from here.
- **experience_add_employment** — Record a place where evidence was produced — a job or a side project. At least company or role is required. Use the returned id to attach achievements with experience_add_achievement.
- **experience_add_achievement** — Record one piece of evidence — the sentence a CV bullet would carry. Only record what the CANDIDATE told you; the server stamps anything created here `manual`, which means they asserted it, and that stamp is what lets it be cited on a CV. A claim already in the bank, under any spelling, is refused as 409 rather than duplicated — so correct the existing one with experience_update_achievement instead of re-adding it.
- **experience_update_employment** — Correct a place already in the bank. Only the fields you pass change — everything else is carried over from what is banked, because the API replaces the whole row. Use this to fix a name, a role, or dates.
- **experience_update_achievement** — Correct an achievement already in the bank — most often a typo in the claim, which cannot be fixed by re-adding it. Only the fields you pass change; metrics and skills REPLACE the whole list when given. Correcting does NOT change who is held to have said it: an agent_inferred achievement stays agent_inferred and stays uncitable on a CV. Confirming it with the candidate then recording what THEY said is the only way it becomes citable.
- **experience_remove_achievement** — Delete one achievement from the bank. There is no undo, so confirm with the candidate first — read it back to them and remove it only on a clear yes. It takes nothing else with it. This is how a duplicate goes: keep the richer entry, remove the other.
- **experience_remove_employment** — Delete a place from the bank. It must hold no achievements — removing a place would delete everything recorded under it, and the server refuses that here (409). To retire a duplicate place, move its achievements to the one being kept with experience_update_achievement, then remove the empty shell. There is no undo; confirm with the candidate first.
- **submit** — Submit a vacancy for moderation. The server stores it as pending and returns it. URL (the dedup key), title, and company are required.
- **my_submissions** — List the caller's own vacancy submissions with their moderation status.
- **jobs_add** — Moderator: create a hand-curated job. URL is the dedup key — re-adding the same URL updates the posting. `description` is stored and rendered as HTML. Requires the moderator role (403 otherwise).
- **jobs_edit** — Moderator: partially update a manual job by slug. Only the provided fields change; the URL identity is not editable. Requires the moderator role (403 otherwise).
- **submissions_pending** — Moderator: list the pending submission review queue. Requires the moderator role (403 otherwise).
- **submission_approve** — Moderator: approve a pending submission, minting a live job. Requires the moderator role (403 otherwise).
- **submission_reject** — Moderator: reject a pending submission with an optional reason. Requires the moderator role (403 otherwise).

## Claude Desktop Quick Installation
Install path detected from listing signals. Uses `npx` (confidence: high):

```json
"mcpServers": {
  "freehire": {
    "command": "npx",
    "args": ["-y","freehire-mcp"],
    "env": {
      "FREEHIRE_TOKEN": ""
    }
  }
}
```

**Requires environment variables:** `FREEHIRE_TOKEN` — the values above are empty placeholders; fill in real credentials before running (see the repository for what each one is for).

## Documentation

## What freehire MCP server does

freehire exposes the freehire job API through MCP. It covers a large normalized catalogue of IT vacancies gathered from company career boards, along with tools for searching, inspecting, and managing opportunities. Authenticated users can mark jobs as applied, save or unsave them, set application stages, add notes, and list tracked vacancies.

The server also supports vacancy-specific CV work. An agent can create or reopen a tailored CV, inspect the fit-analysis context, read the full document, apply validated edits, and render the result as an ATS PDF. A separate experience bank stores employment records and candidate-provided achievements, including provenance that determines whether an item can be cited in a CV.

## How it works

Authentication uses a freehire API key. Call `whoami` first to verify the key before using authenticated operations. The local server reads `FREEHIRE_TOKEN`, or falls back to credentials stored by the freehire CLI at `~/.freehire/creds.json`. The API base URL defaults to `https://freehire.me` and can be overridden with `FREEHIRE_API_URL`.

Start discovery with `facets`. It returns live filter values, vacancy counts, skills, and numeric ranges. Use those values with `search` or `market_fit` rather than guessing filter names or values. Search results include full job descriptions in markdown, so an agent can screen results without fetching each job separately. A returned public slug identifies the vacancy for tools such as `job`, `apply`, `save`, and CV operations.

Geographic filters for region, country, and city are combined as one OR group. Passing a region and a country broadens the search instead of narrowing it. Unsupported filter keys are ignored and reported; retry with any suggested name before using a returned total or market-fit figure.

## Setup and configuration

The package can run locally through `npx`, without a global installation. Add an MCP server entry that runs `npx -y freehire-mcp` and provide the API key through `FREEHIRE_TOKEN`. If the freehire CLI has already authenticated the user, the server can reuse its credentials file instead of receiving the token in the MCP configuration.

A hosted, read-only Streamable HTTP endpoint is available at `https://freehire.me/api/v1/mcp`. Claude Code can install it through the freehire plugin marketplace, while other MCP hosts can add the URL as a custom remote connector. The hosted endpoint is intended for job-search tools; local configuration is the route for the broader authenticated workflow.

## Tools and capabilities

- Discover live facets and search open jobs with keyword and market filters.
- Measure skill coverage and identify missing skills associated with more vacancies through `market_fit`.
- Fetch complete job or company records, including posting descriptions and open company jobs.
- Track applications with `apply`, `stage`, `note`, `my`, `save`, and `unsave`.
- Create, inspect, edit, and render tailored CVs with `cv_tailor`, `cv_context`, `cv_get`, `cv_edit`, `cv_render`, and `cv_list`.
- Maintain candidate evidence with employment and achievement add, update, list, and removal tools.
- Submit vacancies for moderation and, for moderator accounts, create or edit manual jobs and review pending submissions.

CV editing is deliberately constrained. Read `cv_context` and `cv_get` before editing, use evidence IDs from `experience_list` for claims about what the candidate did, and distinguish existing evidence from gaps that require asking the candidate. Edits are atomic: one invalid path or uncited claim rejects the whole batch. Removing experience has no undo, and an employment record must be empty before it can be removed.

_Full upstream README: https://allmcps.com/mcp/freehire/readme_

