Skip to main content
Glama
jppoamaral

job-search-mcp

by jppoamaral
README.md
# job-search-mcp

A local [Model Context Protocol](https://modelcontextprotocol.io) server that turns Claude Desktop into a job-search connector.

## Credit

The search logic and fit-scoring rubric are ported from [MadsLorentzen/ai-job-search](https://github.com/MadsLorentzen/ai-job-search) — specifically its `linkedin-search` / `freehire-search` portal CLIs and its `job-application-assistant` job-evaluation skill. All credit for the original design goes to [Mads Lorentzen](https://github.com/MadsLorentzen). This repo reimplements that logic as a single self-contained Python MCP server (no bun/Node dependency) instead of the original bun/TypeScript CLIs, following the same connector pattern as the sibling [`resume-ats-mcp`](https://github.com/jppoamaral/resume-ats-mcp).

## What it does

Three tools, exposed over MCP:

| Tool | Input | Output |
|---|---|---|
| `search_jobs` | keywords, location, remote/hybrid/onsite, max age, source | matching postings from LinkedIn and/or freehire.me |
| `get_job_detail` | a result's `source` + `id`/URL | full posting text, seniority, employment type, salary (if known) |
| `evaluate_posting` | a job description + candidate profile (text or resume file) | an eligibility-keyword scan plus the five-dimension fit-scoring worksheet, for Claude to fill in |

**search_jobs** — queries LinkedIn's public `jobs-guest` API (HTML, no auth) and the freehire.me aggregator's public REST API (JSON, no auth; ~50 ATS platforms, global/remote coverage).

**get_job_detail** — fetches one posting's full text, for either source.

**evaluate_posting** — like `resume-ats`'s `evaluate_resume`, this tool does *not* compute a fit score itself. It regex-scans the posting for citizenship/PR/security-clearance/sponsorship language (quoting matched sentences) and assembles the ai-job-search framework's eligibility gate, scoring rubric, weighting, and thresholds — structured, deterministic material for Claude to reason over in the conversation, not a replacement for that reasoning.

## How the connector is registered

```json
{
  "mcpServers": {
    "job-search": {
      "command": "/absolute/path/to/mcp-server-jobsearch/.venv/bin/python",
      "args": ["/absolute/path/to/mcp-server-jobsearch/server.py"]
    }
  }
}
```

No `env` block is required — unlike `resume-ats`, this connector has no filesystem default to configure. Optionally set `FREEHIRE_API_URL` if self-hosting a freehire instance.

After editing `claude_desktop_config.json`, fully quit (Cmd+Q) and reopen Claude Desktop — it only reads the file at launch.

## Setup

```bash
cd mcp-server-jobsearch
python3 -m venv .venv
./.venv/bin/pip install -r requirements.txt
```

## Limitations

- LinkedIn's guest search endpoint is unauthenticated and undocumented; markup changes on LinkedIn's side can break parsing without notice.
- `search_jobs`'s `location` filter only applies to the LinkedIn source — freehire's location facets use a region/country taxonomy this client doesn't expose.
- The eligibility scan is keyword-based, not semantic: it flags sentences containing known phrases, it doesn't understand intent. Always verify before treating a match (or its absence) as final.
- Single-machine, single-user: this is a local stdio connector, not a hosted service.

## License

MIT

Maintenance

ActivitySlowing
ResponsivenessNo issues