Skip to main content
Glama
fairquery

company-jobs-feed

Official

Company Jobs Feed: live jobs from Greenhouse, Lever & Ashby (Apify Actor + MCP server)

License: MIT

Live job listings read straight from employers' own applicant-tracking systems through their official public job-board APIs, plus an MCP server so AI agents can use the same data. Every row says when it was verified as currently published on the employer's own hiring system, how old the posting is, whether it has been open a long time, and whether it looks like a repost.

  • Apify Actor: fairquery/company-jobs-feed, pay per result: $0.99 per 1,000 jobs + $0.0005 per board scanned (+ $0.00029 per optional per-job re-check, $0.0019 per company found by discovery). Error, closed and merged rows are free.

  • MCP server (mcp/): four free tools that run on your machine with no token, and one paid tool that runs the Actor in your Apify account.

Honest scope: "currently published" is not "guaranteed to be hiring". The feed gives age, long-open and repost signals so you can filter likely stale or evergreen listings; it does not claim to be ghost-free.

Sources

ATS

API used

Included

Greenhouse

boards-api.greenhouse.io/v1/boards/{slug}/jobs (Job Board API)

Yes

Lever

api.lever.co/v0/postings/{slug} (Postings API)

Yes

Ashby

api.ashbyhq.com/posting-api/job-board/{slug} (public Job Postings API)

Yes

SmartRecruiters

its API host's robots.txt allows only LinkedIn's crawler

No (never contacted)

Recruitee

Careers Site API needs an employer token

No

Workable

public endpoints are documented only for the account's own careers page

No

Workday

no public job API

No

LinkedIn

not contacted at all

No

Company names, domains and careers URLs can be resolved to boards (careers-page links with robots.txt respected, then at most 6 slug probes against the APIs). 51 verified starter boards ship in src/seed.ts.

Related MCP server: io.github.groundtruthtools/ats-jobs-mcp

MCP server

Install

Requires Node.js 20+. From npm: @fairquery/company-jobs-feed-mcp. Claude Desktop / Cursor / VS Code (mcpServers config):

{
  "mcpServers": {
    "fairquery-jobs-feed": {
      "command": "npx",
      "args": ["-y", "@fairquery/company-jobs-feed-mcp"],
      "env": { "APIFY_TOKEN": "<only needed for jobs_search_companies>" }
    }
  }
}

From source: git clone https://github.com/fairquery/company-jobs-feed && cd company-jobs-feed/mcp && npm ci --ignore-scripts && npm run build && node dist/index.js.

Docker: docker build -t fairquery-jobs-feed-mcp . && docker run -i --rm fairquery-jobs-feed-mcp.

Tools

Tool

Cost

What it does

jobs_get_board

free, local

All jobs currently published on one board (ats + slug), normalized and filtered by title, location, country, remote and posted-within. Returns posted_at, age_days, long_open, verified_open_at, apply URL

jobs_find_board

free, local

Resolve a company name, domain or careers URL to its Greenhouse/Lever/Ashby board, with via and confidence

jobs_check_open

free, local

Re-check one job right now: open or closed (detail endpoint; Ashby via the board listing)

jobs_list_seed_boards

free, offline

The verified starter boards (company, domain, ats, slug, verified_at)

jobs_search_companies

paid (Apify PPE)

Many companies at once with discovery, history (first/last seen, new/updated/closed), repost detection, optional re-checks and descriptions. Needs APIFY_TOKEN

Every tool is read-only (readOnlyHint: true, destructiveHint: false), has an output schema, and describes every parameter. Descriptions follow a WHAT / WHEN / WHEN NOT / BEHAVIOR / COST / RETURNS / PARAMETERS / EXAMPLE layout. Without APIFY_TOKEN, initialize, tools/list and the four free tools work; the paid tool returns APIFY_TOKEN_MISSING.

Use the Actor from code

curl -X POST "https://api.apify.com/v2/acts/fairquery~company-jobs-feed/run-sync-get-dataset-items" \
  -H "Authorization: Bearer $APIFY_TOKEN" -H "Content-Type: application/json" \
  -d '{"companies":["stripe.com","ramp.com"],"titleIncludes":["engineer"],"countries":["US"]}'
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('fairquery/company-jobs-feed').call({
    companies: ['https://jobs.lever.co/palantir'],
    countries: ['US'], titleIncludes: ['engineer'], postedWithinDays: 180,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();

Input, output fields, pricing examples, troubleshooting and FAQ: .actor/README.md.

Example job row

Real row from a test run on 2026-10-17 (Ramp, Ashby; abbreviated):

{
  "type": "job", "job_key": "ashby:ramp:34413f8d-26bf-4bbc-8ade-eb309a0e2245", "ats": "ashby", "board": "ramp",
  "company": "Ramp", "title": "Security Engineer, Cloud", "department": "Engineering",
  "locations": ["New York, NY (HQ)", "Remote (Canada)", "Remote (US)", "Miami, FL"], "countries": ["US", "CA"],
  "remote": true, "workplace_type": "hybrid",
  "posted_at": "2026-04-07T17:12:35.753Z", "age_days": 193, "age_basis": "posted_at", "long_open": true,
  "verified_open_at": "2026-10-17T22:54:03.924Z", "first_seen_at": "2026-10-17T22:54:03.924Z", "change": "new", "reposted": false,
  "compensation": { "summary": "$211.4K – $290.6K • Offers Equity", "min": 211400, "max": 290600, "currency": "USD", "interval": "1 YEAR" },
  "apply_url": "https://jobs.ashbyhq.com/ramp/34413f8d-26bf-4bbc-8ade-eb309a0e2245/application", "fingerprint": "646e3148231ba20d"
}

Politeness and security

Only the three documented API hosts are called (HTTPS, no redirects). Careers pages are read only for domains you supply, with robots.txt (RFC 9309), SSRF protection (private IPs refused, DNS pinned) and a 3-page cap. Any 403/429 stops that host for the run. No login, no proxies, no evasion. See SECURITY.md.

Development

See DEVELOPMENT.md. npm test (31 unit tests), npm run mcp:build && npm run mcp:test (MCP build + smoke test).

More from Fairquery

Other Fairquery Actors: https://apify.com/fairquery. One MCP server for several of them: @fairquery/agent-trust-mcp.

License

MIT © 2026 Fairquery. Job data belongs to the employers. Not affiliated with Greenhouse, Lever, Ashby or LinkedIn.

Available Tools

5 tools
jobs_check_openRe-check whether one job is still published (free)A
Read-onlyIdempotent
Inspect

WHAT: Re-check ONE job on the employer's ATS right now and report open or closed. WHEN: Before applying, alerting or contacting about a specific job you got earlier (job_key or ats + slug + jobId). WHEN NOT: Listing jobs (jobs_get_board) or checking many jobs at once (jobs_search_companies with confirmOpen, paid). BEHAVIOR: Greenhouse, Lever: one GET to the documented per-job endpoint; HTTP 404 = closed. Ashby has no per-job endpoint, so the whole board is fetched once and searched for the id (method "board_listing"). "open" means currently published by the employer; it does not prove the role is still being filled. COST: Free. RETURNS: One item {type:"open_check", ats, slug, job_id, status: open | closed, method: detail_endpoint | board_listing, checked_at, source_url} or an error item (HOST_BLOCKED, NETWORK_ERROR: retryable). PARAMETERS: Give either jobKey alone, or ats + slug + jobId; jobKey wins when both are given. EXAMPLE: {"jobKey":"greenhouse:stripe:8172503"} -> {"status":"open","method":"detail_endpoint"}.

ParametersJSON Schema
NameRequiredDescriptionDefault
atsNoRequired. The applicant-tracking system hosting the board: "greenhouse" | "lever" | "ashby". Example: "ashby"
slugNoRequired. Board slug as it appears in the public board URL (case-insensitive): boards.greenhouse.io/<slug>, jobs.lever.co/<slug>, jobs.ashbyhq.com/<slug>. Example: "ramp" or "palantir"
jobIdNoOptional if jobKey is given. The ATS job id (job_id field). Example: "8172503"
jobKeyNoOptional if ats/slug/jobId are given. The job_key from a job row: "<ats>:<slug>:<job_id>". Example: "lever:palantir:10dfc8bc-99ad-4ca2-ab76-853cb90a92c2"

Output Schema

ParametersJSON Schema
NameRequiredDescription
metaNoTool-specific context: board totals, request counts, cost notes
countYesNumber of items in this page
itemsYesResult rows. Each has "type": "job" (job_key, title, company, locations, countries, remote, posted_at, verified_open_at, age_days, long_open, apply_url, source_url, ...), "board", "company", "seed_board", "open_check" or "error" (code, message, retryable)
totalYesTotal items after filters, before paging
offsetYesOffset of the first item in this page
hasMoreYesTrue if more items exist after this page
nextOffsetYesOffset to pass for the next page, or null when done

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well beyond the annotations by explaining per-ATS mechanics (Greenhouse/Lever use a documented detail endpoint where HTTP 404 = closed; Ashby has no per-job endpoint so the board is fetched and searched, method 'board_listing'). It also flags retryable errors (HOST_BLOCKED, NETWORK_ERROR) and an important semantic caveat that 'open' means published, not actively hiring.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Labeled WHAT/WHEN/WHEN NOT/BEHAVIOR/COST/RETURNS/PARAMETERS/EXAMPLE blocks are densely front-loaded with zero filler, and the one-line example anchors the calling convention. Verbose in raw length but every line carries unique information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Although an output schema exists (so returns need not be restated), the description nevertheless names the return fields and the failure modes, plus cost and ATS-specific behavior. An agent has everything needed to call it correctly and interpret the result.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and each parameter is already documented, so the baseline is 3; the description earns above that by stating the either/or contract and the precedence rule ('jobKey wins when both are given'), which the schema does not express. It does not add format/syntax detail beyond the schema's examples.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Starts with a specific verb+resource+scope ('Re-check ONE job on the employer's ATS right now') and explicitly reports the binary outcome (open/closed). It is immediately distinguishable from siblings like jobs_get_board and jobs_search_companies.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Contains explicit WHEN ('before applying, alerting or contacting about a specific job you got earlier') and WHEN NOT sections that name the alternative tools and the condition that selects them (listing vs. bulk-checking with confirmOpen, paid). Nothing is left to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

jobs_find_boardFind which ATS board a company uses (free)A
Read-onlyIdempotent
Inspect

WHAT: Resolve a company name, domain or careers/board URL to its public job board(s) on Greenhouse, Lever or Ashby. WHEN: Before jobs_get_board when you only know the company ("Ramp", "sentry.io", "https://stripe.com/jobs"). WHEN NOT: You already have ats + slug (call jobs_get_board). For many companies plus their jobs in one step use jobs_search_companies (paid). It cannot find Workday, Workable, Recruitee or LinkedIn pages. BEHAVIOR: Runs on your machine. Order: board-URL parsing -> verified starter list -> the company's own website (only for a domain/URL input; robots.txt respected, <= 3 pages, private/internal IPs refused) -> at most 6 GETs against the documented ATS APIs with slug guesses. Stops at the first hit. Nothing is cached or stored. COST: Free. RETURNS: Items of type "board": {ats, slug, company, domain, via (board_url | seed_list | careers_page | slug_probe), confidence (high | medium), board_url}. A slug_probe hit is "medium": the slug exists but may belong to a different company with the same name; check the jobs or pass the URL from the careers page. meta.notes lists robots/blocked/network notes. PARAMETERS: company accepts three forms with different behavior: a board URL is parsed with no network call; a domain or https URL enables the careers-page step; a plain name only uses the starter list and slug probes. EXAMPLE: {"company":"ramp.com"} -> [{"ats":"ashby","slug":"ramp","via":"seed_list","confidence":"high"}].

ParametersJSON Schema
NameRequiredDescriptionDefault
companyYesRequired. Company name, domain or URL, 2-300 chars. Examples: "Ramp", "sentry.io", "https://jobs.lever.co/palantir"

Output Schema

ParametersJSON Schema
NameRequiredDescription
metaNoTool-specific context: board totals, request counts, cost notes
countYesNumber of items in this page
itemsYesResult rows. Each has "type": "job" (job_key, title, company, locations, countries, remote, posted_at, verified_open_at, age_days, long_open, apply_url, source_url, ...), "board", "company", "seed_board", "open_check" or "error" (code, message, retryable)
totalYesTotal items after filters, before paging
offsetYesOffset of the first item in this page
hasMoreYesTrue if more items exist after this page
nextOffsetYesOffset to pass for the next page, or null when done

TDQS

A4.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare read-only, idempotent, non-destructive, open-world, so the bar is lower, yet the description still adds substantial behavior: the resolution order, robots.txt respect, <=3 careers pages, refusal of private/internal IPs, at most 6 ATS API GETs, stopping at first hit, and no caching/storage. This is far beyond the annotations; the only omission is rate-limit/backoff behavior.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Well front-loaded with labeled WHAT/WHEN/WHEN NOT sections and a concrete example, and every section carries information. It is long, and 'COST: Free' duplicates the title's '(free)' label, a minor redundancy in an otherwise dense block.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Despite an output schema existing, the RETURNS section adds value the schema cannot: the 'via' enum values, the confidence semantics, and specifically that a slug_probe hit is only 'medium' and may be the wrong company. Combined with cost, network constraints and meta.notes, an agent has everything needed to call and interpret this tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so a baseline of 3 applies, but the PARAMETERS section adds genuinely new meaning: the three accepted input forms (board URL, domain/URL, plain name) trigger different execution paths, which the schema's flat string description does not convey. The worked example further anchors expected input/output.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Opens with a specific verb+resource ('Resolve a company name, domain or careers/board URL to its public job board(s)') and immediately scopes it to Greenhouse/Lever/Ashby. It explicitly distinguishes itself from the siblings jobs_get_board and jobs_search_companies, so an agent can route without opening any schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The WHEN and WHEN NOT sections give explicit conditions and name the alternatives: use jobs_get_board when you already have ats+slug, jobs_search_companies for bulk paid lookups, and it states the ATSs it cannot find (Workday, Workable, Recruitee, LinkedIn). Nothing is left to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

jobs_get_boardGet live jobs from one ATS board (free)A
Read-onlyIdempotent
Inspect

WHAT: Fetch every job currently published on ONE company board from its official public ATS API (Greenhouse, Lever or Ashby), normalize it and filter it locally. WHEN: You know the board (ats + slug), e.g. from jobs_find_board or a careers-page link, and want its live openings now. WHEN NOT: Many companies at once, history (new/closed/reposted since last run), or careers-page discovery at scale: use jobs_search_companies (paid). Unknown board: use jobs_find_board first. SmartRecruiters, LinkedIn, Workday, Workable and Recruitee are not supported and never contacted. BEHAVIOR: Runs on your machine; one GET to the documented API host only (very large Greenhouse boards: a second, lighter GET). No token, nothing stored, no history: first_seen_at = now and change = null. Any HTTP 403/429 stops that host for the session (kill switch, HOST_BLOCKED error). Lever requests are spaced 1 s apart (its robots.txt Crawl-delay). COST: Free. RETURNS: Paged job rows: job_key, title, company, department, team, locations, countries (+country_basis), remote (+remote_basis), workplace_type, employment_type, compensation (only when the ATS publishes it), posted_at (ATS date or null, never guessed), age_days + age_basis, long_open, verified_open_at, apply_url, job_url, source_url, fingerprint. meta: jobs_total on the board, jobs_matched, requests, complete. PARAMETERS: All filters are AND-ed; values inside one filter are OR-ed. titleIncludes/titleExcludes match whole words ("engineer" does not match "Engineering"). countries uses the ATS's structured country where present (Lever, Ashby) and a place-name list otherwise; rows without any country are dropped when countries is set. postedWithinDays drops rows with posted_at = null. Paging re-fetches the board, so pages from different calls can shift if the employer edits the board in between. EXAMPLE: {"ats":"ashby","slug":"ramp","titleIncludes":["engineer"],"remote":"only"} -> remote engineering roles at Ramp with salary ranges.

ParametersJSON Schema
NameRequiredDescriptionDefault
atsYesRequired. The applicant-tracking system hosting the board: "greenhouse" | "lever" | "ashby". Example: "ashby"
slugYesRequired. Board slug as it appears in the public board URL (case-insensitive): boards.greenhouse.io/<slug>, jobs.lever.co/<slug>, jobs.ashbyhq.com/<slug>. Example: "ramp" or "palantir"
limitNoOptional page size, integer 1-500, default 50
offsetNoOptional items to skip, integer >= 0, default 0; pass nextOffset from the previous response
remoteNoOptional, "any" | "only" | "exclude", default "any"
countriesNoOptional ISO-3166 alpha-2 codes, any-of, case-insensitive. Example: ["US","DE"]
locationsNoOptional, 0-50 strings, any-of. Substring match on location text; "remote" also matches ATS remote flags. Example: ["new york","berlin"]
longOpenDaysNoOptional integer, default 60: rows older than this get long_open = true (a heuristic, not proof of a ghost job)
titleExcludesNoOptional, 0-50 strings, any-of. Drop titles containing any of these. Example: ["intern","manager"]
titleIncludesNoOptional, 0-50 strings, any-of. Keep titles containing any of these whole words/phrases, case-insensitive. Example: ["engineer","data scientist"]
postedWithinDaysNoOptional integer 1-3650: keep jobs whose ATS publish date is at most this many days old. Example: 14
includeDescriptionNoOptional boolean, default false. true adds description_text (plain text, <= 20,000 chars, e-mails/phones removed)

Output Schema

ParametersJSON Schema
NameRequiredDescription
metaNoTool-specific context: board totals, request counts, cost notes
countYesNumber of items in this page
itemsYesResult rows. Each has "type": "job" (job_key, title, company, locations, countries, remote, posted_at, verified_open_at, age_days, long_open, apply_url, source_url, ...), "board", "company", "seed_board", "open_check" or "error" (code, message, retryable)
totalYesTotal items after filters, before paging
offsetYesOffset of the first item in this page
hasMoreYesTrue if more items exist after this page
nextOffsetYesOffset to pass for the next page, or null when done

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations cover the safety profile, but the description adds substantial context annotations cannot: local execution, one GET to a documented host, a 403/429 session kill-switch with HOST_BLOCKED, Lever's 1 s Crawl-delay spacing, no token/storage, and first_seen_at/change semantics. This is rich disclosure beyond the structured hints.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Heavily structured and front-loaded with WHAT/WHEN/WHEN NOT, so an agent gets routing information immediately. It is dense and the RETURNS block partially restates fields that the output schema already carries, which is the main reason it is not a 5.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 12-parameter read tool with full schema coverage and an output schema, this covers the remaining gaps: filter composition rules, paging volatility when the board is edited, supported/unsupported ATSs, and rate-limit behavior. Nothing needed to call it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, but PARAMETERS adds cross-parameter semantics not present in any single schema field: filters are AND-ed while values within a filter are OR-ed, titleIncludes matches whole words, countries drops unmatched rows, and postedWithinDays drops null-dated rows. Only slight overlap with the schema's per-field docs, hence 4 rather than 5.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The WHAT line names a specific verb+resource (fetch every job published on ONE company board from its official public ATS API) plus the scoping constraint (one board, supported ATS list). It explicitly distinguishes itself from jobs_search_companies (many companies/history) and jobs_find_board (board discovery).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

WHEN gives the precondition (you know ats + slug), WHEN NOT enumerates the alternatives and the exact tools to use instead (jobs_search_companies for scale/history, jobs_find_board for unknown boards), and it rules out unsupported ATSs explicitly.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

jobs_list_seed_boardsList the verified starter boards (free, offline)A
Read-onlyIdempotent
Inspect

WHAT: List the bundled starter list of company job boards that Fairquery verified on their official ATS APIs (company, domain, ats, slug, verified_at, jobs_at_verification). WHEN: To pick companies to scan, or to know which names jobs_find_board resolves instantly. WHEN NOT: Live job data (jobs_get_board) or companies not in the list (jobs_find_board). The list is a starting point, not a global index of employers. BEHAVIOR: Offline: reads a static list compiled into the server; no network call. jobs_at_verification is a snapshot from verified_at and goes stale. COST: Free. RETURNS: Paged items {type:"seed_board", company, domain, ats, slug, verified_at, verified_by, jobs_at_verification}; meta.by_ats counts. PARAMETERS: ats narrows the list; omit it for all three systems. Feed ats + slug of any item straight into jobs_get_board. EXAMPLE: {"ats":"lever"} -> Palantir, Spotify, Zoox, Ro.

ParametersJSON Schema
NameRequiredDescriptionDefault
atsNoOptional filter: "greenhouse" | "lever" | "ashby"; default all
limitNoOptional page size, integer 1-500, default 50
offsetNoOptional items to skip, integer >= 0, default 0; pass nextOffset from the previous response

Output Schema

ParametersJSON Schema
NameRequiredDescription
metaNoTool-specific context: board totals, request counts, cost notes
countYesNumber of items in this page
itemsYesResult rows. Each has "type": "job" (job_key, title, company, locations, countries, remote, posted_at, verified_open_at, age_days, long_open, apply_url, source_url, ...), "board", "company", "seed_board", "open_check" or "error" (code, message, retryable)
totalYesTotal items after filters, before paging
offsetYesOffset of the first item in this page
hasMoreYesTrue if more items exist after this page
nextOffsetYesOffset to pass for the next page, or null when done

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover safety (readOnly, idempotent, non-destructive, closed-world), but the description adds substantive behavior beyond them: offline static list with no network call, the free cost, and the staleness caveat that jobs_at_verification is a snapshot from verified_at. That staleness warning is exactly the kind of non-obvious trait that prevents misuse.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The WHAT/WHEN/WHEN NOT/BEHAVIOR/COST/PARAMETERS/EXAMPLE structure is front-loaded and scannable, with no wasted clauses. The RETURNS block partially restates the output schema, which is the only mildly redundant element.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a zero-required-parameter, read-only list tool with an output schema and full annotation coverage, the description supplies everything an agent needs: scope, exclusions, chaining guidance, cost, and the staleness caveat. Nothing material is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, but the description adds genuine meaning: 'ats narrows the list; omit it for all three systems' clarifies the default behavior, and 'feed ats + slug of any item straight into jobs_get_board' documents the intended chaining usage that the schema cannot express.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('List the bundled starter list of company job boards') plus the scope of what was verified (official ATS APIs) and the fields returned. It is immediately distinguishable from jobs_get_board (live data) and jobs_find_board (resolution of arbitrary names).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicit WHEN ('to pick companies to scan, or to know which names jobs_find_board resolves instantly') and WHEN NOT ('live job data (jobs_get_board) or companies not in the list (jobs_find_board)'), naming both alternatives and the condition selecting each.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

jobs_search_companiesSearch and monitor jobs across many companies (paid Apify Actor)A
Read-only
Inspect

WHAT: Run the Fairquery Apify Actor fairquery/company-jobs-feed over many companies or boards: board discovery, search filters, per-board history (first_seen/last_seen, new/updated/closed, repost detection), optional per-job re-checks and descriptions. WHEN: Monitoring a company list ("what is new since yesterday?"), searching the verified starter list, or anything that needs history, closed/repost signals or more than a few boards. WHEN NOT: One board right now (jobs_get_board, free) or one job (jobs_check_open, free). BEHAVIOR: Read-only on job sites; requires APIFY_TOKEN and runs in YOUR Apify account (waits up to 300 s; history is kept in a named key-value store there). Same politeness rules as the free tools: documented ATS APIs only, 403/429 kill switch, robots.txt on careers pages. COST: Paid, pay-per-event, billed to your Apify account: $0.00099 per job row, $0.0005 per board scanned, $0.00029 per re-check (confirmOpen), $0.0019 per company found by discovery; no start fee. Error, closed and merged rows are free. Example: 3 boards, 300 jobs = about $0.30. maxJobs caps the job rows. RETURNS: Paged dataset rows: "job" rows (as jobs_get_board plus first_seen_at, last_seen_at, change, reposted, repost_of, stale_signal, duplicate_of), one "board" row per board (jobs_total, new, updated, closed), "company" rows for discovery, "error" rows (code, message, retryable). PARAMETERS: companies, boards and useSeedList: at least one is required although the schema marks all optional (none -> INPUT_EMPTY, not billed). onlyNew implies history and compares with the last run that used the same stateStoreName, so use one name per saved search; the first run returns everything as new. limit/offset page the returned rows locally; every call starts a new billed run, so fetch the pages you need from one result instead of re-calling. EXAMPLE: {"companies":["stripe.com","ramp.com"],"titleIncludes":["engineer"],"countries":["US"],"onlyNew":true}.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoOptional page size, integer 1-500, default 50
boardsNoOptional. 0-500 exact boards. Example: [{"ats":"lever","slug":"palantir"}]
offsetNoOptional items to skip, integer >= 0, default 0; pass nextOffset from the previous response
remoteNoOptional, default "any"
maxJobsNoOptional integer 1-50000, default 5000: spend cap on billed job rows
onlyNewNoOptional boolean, default false: only new/changed jobs since the last tracked run (plus free closed rows)
companiesNoOptional (see PARAMETERS). 0-200 names, domains or board URLs. Example: ["stripe.com","Ramp","https://jobs.lever.co/palantir"]
countriesNoOptional ISO-2 codes, any-of. Example: ["US","GB"]
locationsNoOptional, 0-50 strings, any-of. Location substring match. Example: ["london"]
confirmOpenNoOptional boolean, default false: re-check each emitted job on its detail endpoint ($0.00029 each, max 200 per run)
departmentsNoOptional, 0-50 strings, any-of. Department/team substring match. Example: ["engineering"]
useSeedListNoOptional boolean, default false: also scan all verified starter boards (each billed as a board)
excludeStaleNoOptional boolean, default false: drop long_open and reposted rows
titleExcludesNoOptional, 0-50 strings, any-of. Whole-word title exclusion. Example: ["intern"]
titleIncludesNoOptional, 0-50 strings, any-of. Whole-word title match. Example: ["engineer"]
stateStoreNameNoOptional, default "fairquery-jobs-feed-state": named key-value store for history in your Apify account
postedWithinDaysNoOptional integer 1-3650 (ATS publish date). Example: 7
includeDescriptionNoOptional boolean, default false: add plain-text descriptions (PII-scrubbed)

Output Schema

ParametersJSON Schema
NameRequiredDescription
metaNoTool-specific context: board totals, request counts, cost notes
countYesNumber of items in this page
itemsYesResult rows. Each has "type": "job" (job_key, title, company, locations, countries, remote, posted_at, verified_open_at, age_days, long_open, apply_url, source_url, ...), "board", "company", "seed_board", "open_check" or "error" (code, message, retryable)
totalYesTotal items after filters, before paging
offsetYesOffset of the first item in this page
hasMoreYesTrue if more items exist after this page
nextOffsetYesOffset to pass for the next page, or null when done

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only provide readOnlyHint/openWorldHint/idempotentHint/destructiveHint, but the description adds a lot beyond them: requires APIFY_TOKEN, runs in the user's own Apify account, waits up to 300 s, persists history in a named key-value store, and documents politeness controls (ATS APIs only, 403/429 kill switch, robots.txt). Detailed pay-per-event cost breakdown and the 'each call starts a new billed run' caveat are disclosed. Nothing here contradicts the annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded labeled sections (WHAT/WHEN/WHEN NOT/BEHAVIOR/COST/RETURNS/PARAMETERS/EXAMPLE) make it skimmable, and for an 18-parameter paid tool every section earns its place. The cost and 'one run, fetch your pages' guidance prevent classic misuse.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the complexity (18 params, paid per-event billing, external Actor run), the description covers purpose, routing, auth, cost, behavior, return-row types, and a concrete example. An output schema exists, yet the RETURNS section still usefully summarizes row kinds. Nothing an agent needs to call it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so 3 is the baseline, but the description adds cross-parameter semantics the schema cannot express: at least one of companies/boards/useSeedList is required even though all are marked optional (else INPUT_EMPTY, unbilled), onlyNew depends on stateStoreName matching the prior run, and limit/offset page rows locally while every call incurs a new billed run. These are meaningful additions, though several per-parameter details (remote, postedWithinDays, excludeStale) are left to the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a precise verb+resource: running the fairquery/company-jobs-feed Actor over many companies or boards, including discovery, filters, and history. It explicitly contrasts scope with siblings jobs_get_board (single board) and jobs_check_open (single job), so an agent can distinguish it without opening any schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The WHEN and WHEN NOT sections name the exact conditions and the free alternatives: use it for monitoring a company list, history/closed/repost signals, or many boards; avoid it for one board (jobs_get_board, free) or one job (jobs_check_open, free). No inference is required.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 5 tool updatesv1.0.1
    • First observedjobs_check_open
    • First observedjobs_find_board
    • First observedjobs_get_board
    • First observedjobs_list_seed_boards
    • First observedjobs_search_companies

TDQS

A4.7/5.0

Scored across 5 tools

Disambiguation4/5

Most tools have clearly distinct purposes: finding a board, fetching a board's jobs, checking one job, listing seed boards, and bulk monitoring. However, jobs_search_companies is a paid superset that functionally overlaps with jobs_get_board, jobs_find_board, jobs_check_open, and jobs_list_seed_boards, creating some potential for misselection despite explicit WHEN NOT guidance.

Naming Consistency5/5

All five tool names use snake_case with a consistent jobs_ prefix and a verb_noun pattern (get_board, find_board, check_open, list_seed_boards, search_companies). The convention is predictable and readable throughout.

Tool Count5/5

Five tools is well-scoped for a company jobs feed server, covering discovery, listing, single-job verification, seed reference, and paid bulk/history operations. Each tool earns its place without redundancy in count.

Completeness4/5

The set covers the main lifecycle: board discovery, live job retrieval, single-job open checks, seed reference, and paid history/monitoring. Minor gaps exist: no free single-job detail retrieval by jobKey, and history/closed/repost signals are only available through the paid tool.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    B
    maintenance
    Live tech-hiring intelligence for AI agents. Search 130K+ open jobs collected daily from ~500 tech companies' own career sites — plus company hiring profiles, tech stacks, salary benchmarks, and skill trends. Five tools work with no account.
    31
    97 npm
    MIT
  • A
    license
    A
    quality
    B
    maintenance
    Enables querying open job postings directly from company applicant-tracking systems (Greenhouse, Ashby, Lever), finding a company's job board, listing and comparing roles, and accessing salary data, all without scraping or API keys.
    3
    48 PyPI
    1
    MIT
  • A
    license
    A
    quality
    C
    maintenance
    Enables real-time job search across thousands of companies' open roles from Greenhouse, Lever, Ashby, and SmartRecruiters, with full-text filtering and company-specific queries, no API key required.
    2
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables users to look up a company's open job postings from public Greenhouse, Lever, and Ashby boards, returning them in one normalized shape with filtering by keyword, location, remote status, and posting date. It also identifies which of those three ATSs hosts a given company's board and how many roles are open there.
    39 npm
    MIT