# Jobs MCP Server – EU, Remote & ATS Job Search for AI Agents (`gazidev/jobs-mcp-server`) Actor

Job-search MCP server for Claude, ChatGPT & Cursor: German federal job board (Arbeitsagentur), EURES (2M EU & Swiss jobs), Jobicy, Remote OK, Arbeitnow, plus any company's Greenhouse, Lever, Ashby, Workable or SmartRecruiters board. Attribution-safe. Pay per call.

- **URL**: https://apify.com/gazidev/jobs-mcp-server.md
- **Developed by:** [Cemal Atakli](https://apify.com/gazidev) (community)
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $5.00 / 1,000 tool calls

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Jobs MCP Server – EU, Remote & ATS Job Search for AI Agents

Give Claude, ChatGPT, Cursor or your own agent **job-search tools over MCP**. One server searches **official and terms-cleared job sources**:

- **Bundesagentur für Arbeit (Jobbörse)**: the German federal job board, about 1M jobs, through its official API.
- **EURES**: about 2M vacancies in 30 EU/EEA countries and Switzerland, run by the European Labour Authority.
- **Company career boards** on **Greenhouse, Lever, Ashby, Workable and SmartRecruiters**. Pass a company slug, a board URL or just the company website.
- **Jobicy, Remote OK and Arbeitnow**, remote and EU job feeds whose terms allow re-use with credit.

It does not scrape LinkedIn, Indeed or Google Jobs. It needs no API key apart from your Apify token, and **you pay only for calls that return something**.

### Tools

| Tool | What it does |
|---|---|
| `search_jobs` | Search jobs by keyword, country (ISO code or name), city, remote, `posted_since` and source. With `sources: auto`, the server picks the sources: the Arbeitsagentur, EURES and Arbeitnow for Germany, EURES for other EU countries, and the remote feeds for `remote: true`. Each result shows the total number of matches per source. |
| `company_jobs` | Every open job at one company, read from its official career board (Greenhouse, Lever, Ashby, Workable, SmartRecruiters). You can filter by keyword, country, city, remote and date. Results include the department, workplace type, salary (when the company publishes it) and the company's own apply link. |
| `job_details` | The full description, salary, contract, deadline, required languages and skills (EURES) and apply link for one job id. |
| `count_jobs` | Hiring and demand signals. For a search, it gives totals per source, with EURES broken down by country or region and Arbeitsagentur by city, profession and working time. For one company, it breaks open jobs down by department, location, workplace and employment type. |
| `list_sources` | The coverage, terms and attribution of each source. **Free.** |

Each job carries `id`, `title`, `company`, `location`, `country`, `remote`, `postedAt`, `employmentType`, `salary` (when given), `applyUrl`, `sourceUrl`, `source` and `attribution`.

### Use cases

- **Job-search assistants**: "Find remote DevOps jobs posted this week that are open to people in Spain."
- **Recruiting and sales intelligence**: "How many engineers is OpenAI hiring, and in which cities?" or "Which companies in Berlin are hiring Python developers?"
- **Labour-market research**: "How many nursing vacancies are open in the Netherlands, and in which regions?" (EURES totals by region, Arbeitsagentur totals by profession.)
- **Career agents and relocation tools**: search the official EU job boards in several countries with one tool.
- **Automations** in n8n, Make or Zapier, or scheduled batch runs that send new jobs to Slack or a sheet.

### Connect it to your AI client (MCP)

The server runs in Apify **Standby mode** and speaks MCP over Streamable HTTP:

```
https://gazidev--jobs-mcp-server.apify.actor/mcp
```

Authenticate with your Apify API token (`Authorization: Bearer <APIFY_TOKEN>`).

**Claude Desktop / Cursor (`mcp.json`):**

```json
{
  "mcpServers": {
    "jobs": {
      "url": "https://gazidev--jobs-mcp-server.apify.actor/mcp",
      "headers": { "Authorization": "Bearer YOUR_APIFY_TOKEN" }
    }
  }
}
```

**Claude Code:** `claude mcp add --transport http jobs https://gazidev--jobs-mcp-server.apify.actor/mcp --header "Authorization: Bearer YOUR_APIFY_TOKEN"`

It also works through the [Apify MCP server](https://mcp.apify.com) and with any client that supports remote MCP servers, such as the OpenAI Agents SDK, LangChain or n8n.

#### Query tips

- `country` accepts `de`, `fr`, `nl`, `pl`, `es`, `ch`, `us`, or names like `"Germany"`. Outside the EU/EEA, `search_jobs` returns remote jobs that are open to that country. Use `company_jobs` for specific employers anywhere.
- `posted_since` accepts a number of days (`7`), `"24h"`, `"2w"` or a date (`"2026-10-01"`).
- `keyword` matches every word you give. Use `OR` for alternatives, for example `"data engineer OR analytics engineer"`. German keywords work best on the Arbeitsagentur, for example `Pflegefachkraft` or `Elektriker`.
- `company_jobs` accepts `greenhouse:stripe`, `lever:palantir`, `ashby:openai`, `https://jobs.lever.co/palantir`, or a website such as `linear.app`, from which the server detects the board.

### Batch mode (normal Actor run)

You can also start the Actor like any other Actor, from the Console, the API, a schedule or an integration. Pick a `tool` and pass `arguments`, or list several `calls`. Each job becomes one dataset row.

```json
{
  "tool": "search_jobs",
  "arguments": { "keyword": "python", "country": "de", "posted_since": 14, "limit": 20 }
}
```

```json
{
  "calls": [
    { "tool": "search_jobs", "arguments": { "keyword": "data engineer", "remote": true } },
    { "tool": "company_jobs", "arguments": { "company": "greenhouse:stripe", "country": "ie" } },
    { "tool": "count_jobs", "arguments": { "keyword": "nurse", "country": "nl" } }
  ]
}
```

#### Output example (dataset row)

```json
{
  "tool": "search_jobs",
  "status": "ok",
  "id": "arbeitsagentur:12265-271357_JB5283341-S",
  "title": "Softwareentwickler Python/C# (m/w/d)",
  "company": "FERCHAU GmbH Niederlassung Friedrichshafen",
  "location": "88046, Friedrichshafen",
  "country": "DE",
  "postedAt": "2026-10-27T00:00:00+00:00",
  "employmentType": "full-time",
  "applyUrl": "https://www.arbeitsagentur.de/jobsuche/jobdetail/12265-271357_JB5283341-S",
  "sourceUrl": "https://www.arbeitsagentur.de/jobsuche/jobdetail/12265-271357_JB5283341-S",
  "source": "Bundesagentur für Arbeit (Jobbörse)",
  "attribution": "Source: Bundesagentur für Arbeit, Jobbörse (arbeitsagentur.de). Link to sourceUrl.",
  "details": { "sourceKey": "arbeitsagentur", "profession": "Softwareentwickler/in", "offerType": "job" }
}
```

A `count_jobs` call for one company returns, for example: `{"company": "OpenAI", "ats": "ashby", "totalOpenJobs": 811, "byDepartment": {"Go To Market": 153, "Applied AI": 118, ...}, "byLocation": {"San Francisco": 570, "New York City": 98, ...}}`.

### Pricing

Pay per event, with no subscription:

| Event | Price | When |
|---|---|---|
| `tool-call` | **$0.005** | A successful `search_jobs`, `company_jobs`, `job_details` or `count_jobs` call that returns a result |
| `job-returned` | $0.0003 | Each job record returned by `search_jobs` or `company_jobs` |
| Actor start | $0.00005 | Once per run or Standby session |

Failed calls, calls that find nothing, invalid input and `list_sources` are **free**. A search that returns 20 jobs costs $0.011. When your maximum charge for a run is reached, the job list is cut short and further calls are refused, so you never pay more than you set.

#### Compared with other job MCP servers on Apify (November 2026)

| Actor | Sources | Price |
|---|---|---|
| **This server** | Arbeitsagentur, EURES, 5 ATS, Jobicy, Remote OK, Arbeitnow | $0.005 per call + $0.0003 per job |
| India Jobs MCP | Indian job platforms | $0.035–0.475 per tool call |
| Google Jobs scraper ("MCP-ready") | Google Jobs | $0.003 per job |
| LinkedIn Jobs MCP Server | LinkedIn | not listed |

### Data sources and attribution

- **Bundesagentur für Arbeit**: the official Jobsuche API. Each job links to its Jobbörse page.
- **EURES**: © European Labour Authority. Re-use is authorised if ELA is acknowledged as the source, so each EURES job carries `source` and `attribution`. Requests are spaced 10 seconds apart, as europa.eu's robots.txt asks.
- **Greenhouse, Lever, Ashby, Workable and SmartRecruiters**: the public job-board APIs behind the companies' own career pages. Links go to the company's board.
- **Jobicy**: redistribution is allowed with credit, and apply links must point to the original Jobicy listing, which `applyUrl` does. Responses are cached for 1 hour.
- **Remote OK**: link back to the Remote OK listing and mention Remote OK. Only the latest ~100 public jobs are available. Cached for 30 minutes.
- **Arbeitnow**: free public API, used with a link back. Cached for 30 minutes.
- **Not used**: Himalayas and Remotive, whose terms forbid passing their jobs to other boards or aggregators, and LinkedIn, Indeed and Google Jobs.

When you show jobs to users, keep `source`, `sourceUrl` and `applyUrl` unchanged.

### FAQ

**Which countries are covered?** Germany in depth (Arbeitsagentur, EURES and Arbeitnow), all 30 EURES countries (EU, Iceland, Liechtenstein, Norway and Switzerland), remote jobs worldwide, and any company on the five supported ATS platforms, wherever it hires.

**Why do totals differ from the number of jobs returned?** `totalAvailable` is the number of matches at the source. A call returns up to `limit` jobs, and you can raise `limit` (max 100) or narrow the query.

**Are there duplicates?** Many German employers post on both the Arbeitsagentur and EURES. Results are de-duplicated by title and company within a call.

**Is the UK covered?** The UK is not part of EURES. Use `company_jobs` for UK employers, or `search_jobs` with `remote: true`.

**Is the data fresh?** The Arbeitsagentur, EURES and company boards are queried live. The remote feeds are cached for 30–60 minutes because of their polling rules.

### Use with AI agents / Apify MCP

This Actor *is* an MCP server. Connect it directly (see above), or add it through [mcp.apify.com](https://mcp.apify.com) next to other Apify Actors. In batch mode, call it from the Apify API, the Python or JS client, or any integration.

# Actor input Schema

## `tool` (type: `string`):

Which tool to run in batch mode. With neither tool nor calls, a demo search (python jobs in Germany) runs.

## `arguments` (type: `object`):

Arguments for the tool. Examples: search_jobs {"keyword": "python developer", "country": "de", "location": "Berlin", "remote": null, "posted_since": 7, "limit": 20} (country: ISO code or name; remote: true/false; sources: \["arbeitsagentur", "eures", "jobicy", "remoteok", "arbeitnow"] or auto); company_jobs {"company": "greenhouse:stripe", "keyword": "engineer", "country": "ie"} (also a board URL or a company website); job_details {"job_id": "arbeitsagentur:10000-1183300826-S"}; count_jobs {"keyword": "nurse", "country": "nl"} or {"company": "lever:palantir"}; list_sources {}.

## `calls` (type: `array`):

Run several tool calls in one run (max 50): \[{"tool": "search_jobs", "arguments": {"keyword": "data engineer", "remote": true}}, {"tool": "company_jobs", "arguments": {"company": "ashby:openai"}}]. EURES requests are spaced 10 s apart (europa.eu crawl-delay).

## Actor input object example

```json
{
  "tool": "search_jobs",
  "arguments": {
    "keyword": "python",
    "country": "de",
    "posted_since": 14,
    "limit": 20
  }
}
```

# Actor output Schema

## `jobs` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "tool": "search_jobs",
    "arguments": {
        "keyword": "python",
        "country": "de",
        "posted_since": 14,
        "limit": 20
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("gazidev/jobs-mcp-server").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "tool": "search_jobs",
    "arguments": {
        "keyword": "python",
        "country": "de",
        "posted_since": 14,
        "limit": 20,
    },
}

# Run the Actor and wait for it to finish
run = client.actor("gazidev/jobs-mcp-server").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "tool": "search_jobs",
  "arguments": {
    "keyword": "python",
    "country": "de",
    "posted_since": 14,
    "limit": 20
  }
}' |
apify call gazidev/jobs-mcp-server --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,gazidev/jobs-mcp-server"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/o245vubyvCHMjI1h5/builds/gUZJ8ugS4KptDemM9/openapi.json
