Nordic/Baltic operations jobs right now:Open ops jobs:
For developers

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.

No API key required 3 read-only tools 60 requests / hour / IP
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.

Why this exists: rather than fighting scrapers with bot detection and blocking, JobMatch gives anyone a documented, structured, rate-limited way in — one that's genuinely easier to use than parsing HTML. If you're building something on top of JobMatch's data, this is the door to use.

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:

config
{
  "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:

curl
# 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).

ParameterTypeDescription
querystringoptionalFree text matched against title, company, tags, and location.
countrystringoptionalExact match, e.g. "Denmark", "Sweden".
tagsstring[]optionalJob must have every tag listed.
remoteTypestringoptionalExact match: "Remote", "Hybrid", or "On-site".
employmentTypestringoptionalExact match, e.g. "Full-time".
limitintegeroptional1–50. Default 20.
response (truncated)
{
  "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.

ParameterTypeDescription
idintegerrequiredA 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.
  • applyUrl is 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.

Contact

Let's talk

Building something with this, or have a request for what it should expose next? Reach out.

k@kennethjensen.me

I read every message and reply personally, usually within a few hours.