Skip to main content
Glama
wmh
by wmh

job-source-mcp

MCP server that searches job listings from Taiwanese job boards and returns normalized results.

Supported sources:

  • 104 — uses curl_cffi Chrome TLS impersonation; no login required

  • Yourator — uses Playwright headless browser; no login required

  • CakeResume — uses curl_cffi Chrome TLS impersonation; no login required

  • LinkedIn — uses the public guest job-search API via curl_cffi; no login required

Removed source: Meet.jobs was supported until the service permanently shut down on 2026-06-30 (the site now serves only a closure announcement). The adapter was removed in July 2026.

Installation

python -m venv .venv
source .venv/bin/activate
pip install -e .
playwright install chromium

To also enable Chrome cookie injection for Yourator (improves result quality on accounts with browsing history):

pip install -e ".[cookies]"

Related MCP server: JobSpy Cowork MCP Server

Usage with Claude Code

Add to your .mcp.json:

{
  "mcpServers": {
    "job-source": {
      "type": "stdio",
      "command": "/path/to/.venv/bin/job-source-mcp"
    }
  }
}

MCP tools

ping

Health check. Returns {"ok": true}.

session_status

Returns readiness of each source. All sources work without login.

search_jobs

Search job listings across one or more sources.

{
  "keyword": "golang backend",
  "source": "all",
  "page": 1,
  "limit": 20,
  "location": "台北市"
}

source accepts: "all", "104", "yourator", "cakeresume", "linkedin".

Response:

{
  "keyword": "golang backend",
  "source": "all",
  "count": 12,
  "jobs": [
    {
      "source": "104",
      "id": "abc123",
      "title": "Golang Backend Engineer",
      "company": "Acme Corp",
      "location": "台北市信義區",
      "salary": "80,000–120,000",
      "url": "https://www.104.com.tw/job/abc123",
      "posted_at": "20260601",
      "tags": ["Go", "Kafka", "Redis"],
      "description": "..."
    }
  ],
  "rate_limited": [],
  "errors": []
}

rate_limited lists any source that returned HTTP 429 even after backing off (each entry: {"source", "retry_after"}). It exists so a throttled source is never confused with one that simply found nothing: if count is 0 and rate_limited is empty, the search genuinely matched no jobs; if a source appears in rate_limited, its 0 results mean "couldn't fetch", not "no matches". Rate-limited sources also appear in errors with "type": "rate_limited" (other failures use "type": "error").

How it works

104 — Direct API call to https://www.104.com.tw/jobs/search/api/jobs using curl_cffi with impersonate="chrome110". This bypasses Cloudflare bot detection by presenting a real Chrome TLS fingerprint. No login or session cookie required.

Yourator — Playwright launches a headless Chromium browser, navigates to https://www.yourator.co/jobs?term=<keyword>, and intercepts the backend API response (GET /api/v4/jobs?term=<keyword>). The browser's persistent profile is stored in ~/.config/job-source-mcp/profiles/yourator/ so it is reused across runs.

If browser-cookie3 is installed, Yourator also injects cookies from your local Chrome profile, which may improve result relevance for logged-in users.

CakeResume — Fetches the search results page https://www.cakeresume.com/jobs?q=<keyword> (filtered to zh-TW) with curl_cffi using impersonate="chrome110", then parses the embedded Next.js __NEXT_DATA__ JSON blob to extract listings. No login or session cookie required. CakeResume caps each page at ~10 results. Returned url uses the cakeresume.com/jobs/<slug> path; the canonical clickable form is cake.me/companies/<company-slug>/jobs/<slug>.

LinkedIn — Calls the public guest job-search endpoint https://www.linkedin.com/jobs-guest/jobs/api/seeMoreJobPostings/search with curl_cffi (impersonate="chrome110") and parses the returned HTML job cards with BeautifulSoup. No login or session cookie required. Pagination uses an offset (start = (page - 1) * 10); each request yields ~10 cards. When location is omitted it defaults to Taiwan. Guest cards do not include a job description (left empty) and rarely include salary. LinkedIn is the most rate-limit-sensitive source, so requests use an adaptive low-frequency limiter (see Rate limiting).

Configuration

Environment variable

Default

Description

JOB_SOURCE_DIR

~/.config/job-source-mcp

Base directory for Playwright browser profiles

Rate limiting

The 104, Yourator, and CakeResume adapters include a random delay (1.5–4 s) per request to simulate human browsing speed.

LinkedIn uses an adaptive process-wide rate limiter (job_source_mcp/throttle.py). It serializes outbound requests with a minimum spacing (≥ 8 s, plus jitter) so the server never calls this API at high frequency. When a source returns HTTP 429, the limiter escalates the interval and keeps it escalated (doubling, up to 120 s for LinkedIn) and backs off before a single retry — the response to throttling is to call less often, not to retry harder. The interval only relaxes gradually after sustained success.

When searching multiple keywords, call search_jobs sequentially rather than in parallel.

Development

Install with the dev extras, then run the linter and tests:

pip install -e ".[dev]"
ruff check .        # lint
pytest              # tests (no network access required)

The test suite mocks the network layer (curl_cffi sessions) and drives the adapters' parsers with fixtures, so it runs offline in well under a second. CI (.github/workflows/ci.yml) runs the same ruff check + pytest across Python 3.11–3.13 on every push and pull request.

License

MIT

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    B
    maintenance
    Searches 104 job listings with natural-language filters and retrieves full postings via MCP tools.
    3
    18 PyPI
    27
    MIT
  • F
    license
    Not graded
    quality
    B
    maintenance
    Enables searching real job listings from multiple job boards (Indeed, LinkedIn, Glassdoor, Google Jobs, etc.) through a single MCP tool, designed for use as a custom connector in Claude Cowork.
    -
  • A
    license
    A
    quality
    B
    maintenance
    Enables natural-language search and retrieval of Taiwan 104 job bank listings, including job details and company-specific openings, with filters for location, salary, experience, and remote work through an MCP interface.
    4
    170 npm
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables natural-language job search and aggregation from multiple recruitment websites with zero configuration, providing filtered results and standardized output for AI assistants.
    29 npm
    ISC