Talk to JobMatch's job data directly.
A free, read-only MCP server over the same Nordic/Baltic Operations job data that powers the search page and analytics — built as the sanctioned alternative to scraping the site.
https://jobmatch-mcp.kennethj.workers.dev/mcp
Overview
MCP (Model Context Protocol) is an open standard for connecting an AI agent — Claude, or anything else that speaks it — to an external tool or data source in a structured way, instead of that agent having to scrape or guess at a website's HTML.
This server exposes three read-only tools over JobMatch's own listing and market-stats data: search by keyword, country, remote type, or tag; look up a single listing; or pull the aggregate market snapshot shown on the Job Analytics page. It reads only what's already public — nothing here is behind a login, and nothing exposed here isn't already visible on the site itself.
Quickstart
The server speaks the MCP Streamable HTTP transport. Point any MCP-compatible client at the endpoint above, or call it directly as JSON-RPC over HTTPS.
Option A — add it to an MCP client
For Claude Desktop, Claude Code, or any client that supports a remote MCP server by URL, add:
{
"mcpServers": {
"jobmatch": {
"url": "https://jobmatch-mcp.kennethj.workers.dev/mcp"
}
}
}
Option B — call it directly
Any HTTP client works. A tool call is a single JSON-RPC request:
# search_jobs curl https://jobmatch-mcp.kennethj.workers.dev/mcp \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -d '{ "jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": { "name": "search_jobs", "arguments": { "country": "Sweden", "tags": ["Manager"], "limit": 5 } } }'
No initialize handshake to manage by hand — the server is stateless, so every request is self-contained. An MCP client library will still perform the standard handshake automatically; that's expected and handled.
Authentication & rate limits
No API key, no login. Every request is anonymous and counted by IP address: 60 requests per hour, fixed window. Going over it returns an HTTP 429 with a plain JSON body:
{ "error": "Too many requests. Try again later." }
An opt-in API key for higher limits is planned but not built yet — see Roadmap.
Tools
All three tools are read-only and side-effect-free. Every job record's applyUrl routes through JobMatch's own click-tracked redirect rather than a raw scraped link — that's deliberate, and it's the same link the site itself renders.
toolsearch_jobs
Search active listings. All parameters are optional and combine with AND. Results are sorted newest-posted-first — this version does plain keyword matching, not semantic ranking (see Roadmap).
| Parameter | Type | Description | |
|---|---|---|---|
| query | string | optional | Free text matched against title, company, tags, and location. |
| country | string | optional | Exact match, e.g. "Denmark", "Sweden". |
| tags | string[] | optional | Job must have every tag listed. |
| remoteType | string | optional | Exact match: "Remote", "Hybrid", or "On-site". |
| employmentType | string | optional | Exact match, e.g. "Full-time". |
| limit | integer | optional | 1–50. Default 20. |
{
"count": 143,
"returned": 1,
"results": [
{
"id": 2268,
"jobTitle": "Operations Manager",
"company": "Flow Intimates",
"location": "Frederiksberg",
"country": "Denmark",
"city": "Frederiksberg",
"remoteType": null,
"employmentType": null,
"salaryMin": null,
"salaryMax": null,
"currency": null,
"sourceSite": "jobindex.dk",
"datePosted": "2026-09-24",
"tags": ["Manager"],
"applyUrl": "https://jobmatch-worker.kennethj.workers.dev/go/2268"
}
]
}
toolget_job
Look up a single listing by id — the same shape search_jobs returns per result.
| Parameter | Type | Description | |
|---|---|---|---|
| id | integer | required | A job id, as returned by search_jobs. |
An unknown id doesn't error — it returns isError: true with a plain message, so a bad id is a normal tool result to handle, not an exception.
toolget_market_stats
No parameters. Returns the same aggregate, anonymised snapshot shown on Job Analytics — totals, country/tag/seniority breakdowns, and week-over-week trend. No per-listing detail; use search_jobs for that.
Data & caching
- Source data refreshes on JobMatch's own scraping schedule — roughly every 2 days.
- Responses are cached at the edge for 5 minutes, so a burst of calls doesn't cause redundant fetches. This doesn't affect freshness beyond that window.
- Embeddings used for the site's own semantic search are never included in tool responses — they're meaningless outside that specific model and would only inflate every response.
applyUrlis always a tracked redirect, never the raw scraped URL — clicking through counts the same way a click from the site itself does.
Terms
Free to use. If you build something public on top of this data, an attribution link back to kennethjensen.me/jobmatch is appreciated, not required. Don't use it to rebuild a competing scrape of the underlying sites JobMatch itself tracks — the point of this server is to be a better way to use JobMatch's own data, not a shortcut around everyone else's.
Roadmap
This is a phase-1 build. Not yet done, roughly in order:
- An opt-in free API key for higher rate limits.
- Semantic/embedding-ranked search, matching what the site's own search page does.
- A "new listings" subscription or webhook tool, so a real-time integration doesn't need to poll.
Something missing, or a rough edge you hit integrating? Get in touch.
Let's talk
Building something with this, or have a request for what it should expose next? Reach out.
I read every message and reply personally, usually within a few hours.