# ATS Jobs MCP Server: Greenhouse, Lever, Ashby & More (`guayox/ats-jobs-mcp-server`) Actor

MCP server for AI agents: find which job board a company uses and search its open jobs on Greenhouse, Lever, Ashby, Workable or Personio, with salary ranges. Works with Claude, Cursor and any MCP client.

- **URL**: https://apify.com/guayox/ats-jobs-mcp-server.md
- **Developed by:** [Eduardo Ruiz](https://apify.com/guayox) (community)
- **Categories:** Agents, Jobs
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.60 / 1,000 jobs

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

## ATS Jobs MCP Server: open jobs and salaries for AI agents

Give Claude, Cursor or any MCP client live access to company job boards. Ask "what engineering roles is Notion
hiring for?" and the agent finds which applicant tracking system (ATS) the company uses, then reads its open jobs
from **Greenhouse**, **Lever**, **Ashby**, **Workable** or **Personio**, with **salary ranges** where the company
publishes them. Recruiters, sales teams tracking hiring signals, job seekers and market researchers use it to put
hiring data straight into their AI workflows.

### What can it do?

- **Find a company's job board:** give a company name and it tries the five platforms for you (for example
  "notion" is on Ashby, "airbnb" on Greenhouse). Free: nothing is charged.
- **Search open jobs:** one or more companies (names or job board URLs), with optional title and location
  keywords. Each job comes with title, company, location, department, workplace and employment type, salary range,
  posting date and the link to apply.
- **Short or full answers:** a compact summary per job by default, or the description too (first 1,500
  characters), so answers stay within your agent's context.
- **Polite and clean:** it reads only each platform's public job feed, respects robots.txt and rate limits, and
  returns no personal data (e-mail addresses and phone numbers in descriptions are replaced with `[removed]`).

### Tools

| Tool | Arguments | Returns | Charged |
|---|---|---|---|
| `find_job_board` | `company` | the board (for example `ashby:notion`), its platform and the number of open jobs | No |
| `search_jobs` | `companies`, `title_keywords`, `location_keywords`, `max_results` (default 25, at most 100), `include_descriptions` | the jobs found and the board used for each company | Per job returned |

### How to connect

The server runs in Apify's Standby mode: it starts when your agent calls it and stops when idle. Its MCP endpoint
is shown on the Actor's page in Apify Console, and has this form:

```
https://<your-apify-username>--ats-jobs-mcp-server.apify.actor/mcp
```

Authenticate with your [Apify API token](https://console.apify.com/settings/integrations) as a Bearer token.

**Claude Code:**

```bash
claude mcp add --transport http ats-jobs https://<your-apify-username>--ats-jobs-mcp-server.apify.actor/mcp \
  --header "Authorization: Bearer <your-apify-token>"
```

**Any MCP client** that supports Streamable HTTP: use the URL above with the header
`Authorization: Bearer <your-apify-token>`.

You can also run the Actor normally from Apify Console or the API. A normal run reads the job boards in its input
(for example `["airbnb", "lever:zoox", "ashby:warp"]`) and writes every open job to its dataset.

### How much does it cost?

You pay per job returned: $1.60 per 1,000 jobs, the same as a normal run. `find_job_board` is free. While the
server runs in Standby mode you also pay Apify's platform usage for the run, as for every Standby Actor; it stops
after a short idle time. Set a maximum cost per run, and `search_jobs` stops when it is reached.

### Example

Ask your agent: *"Is Warp hiring account executives, and what do they pay?"* The agent calls:

```json
{"tool": "search_jobs", "arguments": {"companies": ["warp"], "title_keywords": ["account"], "max_results": 10}}
```

and gets back, for each job (here a real answer):

```json
{
    "title": "Account Executive",
    "company": null,
    "location": "New York",
    "department": "Sales",
    "workplace_type": "onsite",
    "employment_type": "Full-time",
    "salary_min": 160000,
    "salary_max": 200000,
    "salary_currency": "USD",
    "salary_interval": "per-year-salary",
    "absolute_url": "https://jobs.ashbyhq.com/warp/6fa4373f-2f5e-4fa3-9ce5-e662275ebba8",
    "first_published": null,
    "updated_at": "2025-12-04T18:43:07.001+00:00",
    "platform": "ashby",
    "board_token": "warp",
    "job_id": "6fa4373f-2f5e-4fa3-9ce5-e662275ebba8"
}
```

### FAQ

**Is it legal to use this data?** The server reads only the platforms' public job feeds, the same jobs each company
shows on its public careers page:

- **Greenhouse:** the [Job Board API](https://docs.greenhouse.io/job-board.html). Greenhouse's documentation says
  this data is publicly available and its GET endpoints need no authentication.
- **Lever:** the [Postings API](https://github.com/lever/postings-api). Lever's documentation says published
  postings "are publicly viewable" and "may be scraped by third parties".
- **Ashby:** the [Public Job Posting API](https://developers.ashbyhq.com/docs/public-job-posting-api). A salary is
  returned only when the company shows pay on its posting.
- **Workable:** the public jobs endpoint described in Workable's help centre
  ([Using the Workable API to create a careers page](https://help.workable.com/hc/en-us/articles/115012771647)).
- **Personio:** the XML job feed in Personio's
  [developer documentation](https://developer.personio.de/docs/retrieving-open-job-positions).

Ashby's, Workable's and Personio's documentation does not address third-party use either way. The server needs no
login, checks robots.txt before each request, keeps to a polite request rate, and returns no personal data. Check
that your own use of the job postings suits your purpose and jurisdiction.

**A company was not found.** It may not use one of these five platforms, or its board has a different name. Ask
the agent to use the job board URL from the company's careers page instead (for example
`https://jobs.lever.co/<company>`).

**Why is `company` sometimes empty?** Lever's and Ashby's feeds do not include the company's display name; every
job carries its `board_token`, which identifies the company.

**Something is not working.** Open an issue on the Actor's **Issues** tab; it is monitored daily.

# Actor input Schema

## `boardTokens` (type: `array`):

Companies to read. Greenhouse: a board token (the part after boards.greenhouse.io/, for example "airbnb") or any Greenhouse job board URL. Lever: "lever:<company>" (for example "lever:zoox") or any jobs.lever.co URL; use "lever-eu:<company>" or a jobs.eu.lever.co URL for EU-hosted boards. Ashby: "ashby:<company>" (for example "ashby:ramp") or any jobs.ashbyhq.com URL. Workable: "workable:<account>" (for example "workable:blueground") or any apply.workable.com URL. Personio: "personio:<company>" (for example "personio:tado") or any jobs.personio.com or jobs.personio.de URL. Put one board per line (several on a line, separated by commas, also work). Each board is one request.

## `includeContent` (type: `boolean`):

Return each job's description (HTML and plain text) with its departments and offices. Turn off for a lighter list of titles, locations and links only.

## `titleKeywords` (type: `array`):

Keep only jobs whose title contains at least one of these words (not case-sensitive). Leave empty for every job.

## `locationKeywords` (type: `array`):

Keep only jobs whose location or office contains at least one of these words, for example "Remote" or "London" (not case-sensitive). Leave empty for every location.

## `onlyNew` (type: `boolean`):

Return, and charge for, only jobs that earlier runs with the same boards and keywords have not returned yet. Turn it on and schedule the Actor (for example daily) to get a feed of newly posted jobs; a run with no new jobs charges no results. The first run returns every open job.

## `monitorName` (type: `string`):

Optional, for "Only new jobs". Runs with the same name share one memory of returned jobs, even when you add or remove boards. Without a name, the memory follows the boards and keywords.

## `maxResults` (type: `integer`):

Stop after this many jobs. Each job is charged once.

## `maxRequestsPerSecond` (type: `number`):

Polite rate limit for the job board APIs. At most 1 request per second, which is what Lever's robots.txt asks for; the Actor also honours Retry-After and backs off on errors.

## Actor input object example

```json
{
  "boardTokens": [
    "airbnb",
    "lever:zoox",
    "ashby:warp",
    "workable:blueground",
    "personio:ottonova"
  ],
  "includeContent": true,
  "titleKeywords": [],
  "locationKeywords": [],
  "onlyNew": false,
  "maxResults": 1000,
  "maxRequestsPerSecond": 1
}
```

# Actor output Schema

## `results` (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 = {
    "boardTokens": [
        "airbnb",
        "lever:zoox",
        "ashby:warp",
        "workable:blueground",
        "personio:ottonova"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("guayox/ats-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 = { "boardTokens": [
        "airbnb",
        "lever:zoox",
        "ashby:warp",
        "workable:blueground",
        "personio:ottonova",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("guayox/ats-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 '{
  "boardTokens": [
    "airbnb",
    "lever:zoox",
    "ashby:warp",
    "workable:blueground",
    "personio:ottonova"
  ]
}' |
apify call guayox/ats-jobs-mcp-server --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,guayox/ats-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/teJdfB2ZmjtDYsLDz/builds/FU4xg4eRdbd6JNclj/openapi.json
