Skip to main content
Glama

Fairquery Agent Trust & Data Safety

Search the starter list by place and role (free, not every employer)

jobs_search_by_location
Read-onlyIdempotent

Indexed Jobs search is LIVE (paid, on your own Apify token): one call searches 8,800+ Greenhouse, Ashby and Lever company boards, with radius and salary filters, from a fresh daily index (not a live scrape of a few boards). Run it as the Apify Actor https://apify.com/fairquery/jobs-index-search or the MCP https://mcp.getfairquery.com/jobs-index/mcp (send your Apify token). New Apify accounts get a $5 starter credit. This free tool stays free and live-scans the 135-board starter list. WHAT: Free search of the bundled starter list (135 public Greenhouse, Lever and Ashby boards). Not every employer and not every company. No company name. Live jobs from each board's official public API. Same normalized "job" rows as jobs_get_board. One call may cover only part of the list. WHEN: The user asks for jobs by place and/or role and does not name a company. Call THIS tool immediately. Do not ask the user for a company. Do not call jobs_get_board or jobs_find_board first. Examples: "avionics jobs in Baltimore MD", "avionics jobs in Costa Mesa", "remote RN jobs in PA", "nursing jobs in Maryland". Put the place in locations (Baltimore, Baltimore MD, MD, Maryland, BWI, PA, Costa Mesa) or countries, or set remote to "only". Put a skill or role that may not be the job title in descriptionIncludes (avionics, nurse), not in titleIncludes. WHEN NOT: The user already named one company or board (jobs_find_board, then jobs_get_board). They want employers outside this starter list, radius or salary filters: paid indexed search (8,800+ boards, fresh daily index) is live as the Apify Actor fairquery/jobs-index-search or https://mcp.getfairquery.com/jobs-index/mcp (own Apify token). jobs_search_companies is offline here and does not run any paid Actor. This tool does not search all companies. The free limits stay 135 starter boards. BEHAVIOR: Runs on this Fairquery-hosted Worker (Cloudflare), not on the caller's machine; inputs leave the client. This Worker's code is designed not to store inputs or results. Each starter-list board slug is sent to its public ATS host. Requires a place signal or it returns INVALID_INPUT and does not fetch: a non-empty locations list, a non-empty countries list, or remote "only". Reads starter boards with the same client, kill switch and rate limits as the other free tools (at most 2 requests in flight per host, Lever spaced 1 s apart, up to 4 boards at a time). A board GET that fails before any job is read (network error, timeout, or HTTP 5xx) is retried once after about 300 ms and that retry is named in meta.notes. HTTP 403 and 429 are not retried. A second failure is skipped and named in meta.notes. The retry is skipped when the CPU budget, the wall clock, or the request cap is already spent. Greenhouse matches title and department on the lite list before any body request. A body is a second request to that same host only when a description keyword is still missing from the title and department, or includeDescription needs the text, and the lite list already has a job in the place. A Greenhouse board with more than 1000 jobs does not get a body request (the Anduril body is about 44 MB and does not fit the 128 MB isolate). Those boards are listed in meta.title_only_boards and return title and department matches only. Lever and Ashby descriptions are in the one list response. Each board is read in small slices, one job at a time. Description fields are not copied unless descriptionIncludes or includeDescription needs them. A text field longer than 20,000 characters is cut before matching and named in meta.notes. A board that is still too large is cut off and the scan continues. A missing board (BOARD_NOT_FOUND) is skipped. A board error is skipped and named in meta.notes. HOST_BLOCKED stops that host for the session; other hosts continue. The scan stops early on a 25 second wall clock, on the CPU work budget (12,000 ms estimated, a hard ceiling, 8,000 JSON characters per millisecond plus 0.08 ms per row built, because the hosted Worker clock does not advance during synchronous parsing; Paid Workers default to about 30 seconds of CPU and this soft-stop returns JSON before that; one call does not run unbounded), on a cap of 200 matched rows, or after 300 ATS requests (a hard ceiling: 135 starter boards take one lite request each, plus a Greenhouse body only when a description is still needed and the board has at most 1000 jobs, at most about 223 requests; Paid Workers allow 10,000 subrequests). It returns the jobs already matched (meta.partial true, meta.stop_reason "time_budget", "cpu_budget", "row_cap" or "subrequest_budget", meta.cost_usd 0). A scan error still returns that JSON (meta.stop_reason "error"); it does not throw a Server error and it does not invent jobs. Nothing is stored. offset pages rows inside this response. It does not continue the board walk. Pass boardCursor from meta.next_board_cursor, with the same place and keywords, to read boards this call did not start. next_board_cursor is null only when every board from the current board_cursor through the end was started, or no boards remain. Do not call again when it is null. A cpu_budget, subrequest_budget, time_budget, or row_cap stop before the end of the list sets it to the next unstarted index. A board error is skipped and named in meta.notes; it does not rewind the cursor behind boards this call already started. COST: No APIFY_TOKEN, no billing. meta.cost_usd is 0. RETURNS: Paged "job" rows. meta.notice (also meta.notes[0]) is the indexed search note: paid indexed search is live, covers 8,800+ boards with radius and salary filters from a fresh daily index, and runs as the Apify Actor https://apify.com/fairquery/jobs-index-search or the MCP https://mcp.getfairquery.com/jobs-index/mcp on your own Apify token. When meta.partial is true or the board walk is incomplete, meta.notice starts with how many of meta.boards_total boards this call finished. Also meta.boards_total, meta.boards_reached (boards this call started), meta.boards_scanned (boards that finished), meta.boards_ok, meta.boards_failed, meta.boards_skipped, meta.jobs_matched, meta.partial, meta.complete, meta.cut, meta.board_cursor, meta.next_board_cursor, meta.notes and meta.cost_usd. meta.stop_reason is set when partial is true. meta.title_only_boards lists Greenhouse boards whose body was skipped. meta.complete is true when this call started every board from board_cursor through the end and did not hit a budget. meta.next_board_cursor is the first starter index this call did not start, or null when nothing is left to resume. meta.cut is true when coverage is narrower than a full read. When jobs_matched is 0 after at least one board answered, meta.suggestions lists the title and description tokens tried, place aliases that had open roles, a sample of open titles in the requested place with the keyword removed, and a note that this list is not every employer and which ATS are covered. Suggestions are not job listings. Relay meta.notice to the user. PARAMETERS: At least one of locations, countries or remote "only" is required. There is no company parameter. titleIncludes and titleExcludes are whole words on the title only. descriptionIncludes is whole-word on the title, the department, or the scrubbed description, so "avionics" matches an Avionics department or Electrical Technician when the body says avionics. Do not put the same word in both titleIncludes and descriptionIncludes. "RN" matches RN, not "Registered Nurse". titleRegex is optional. postedWithinDays drops rows with no ATS date. includeDescription adds scrubbed plain text to the rows; descriptionIncludes still matches when it is false and does not add that text. Location terms expand US state names and codes both ways (MD and Maryland, PA and Pennsylvania) and metro aliases (NYC, SF, LA, DC, Tampa Bay, Baltimore / Baltimore MD / BWI). Two-letter codes match as whole tokens. countries stays ISO-2. boardCursor is an index into the starter list, not a row offset. EXAMPLE: {"locations":["Costa Mesa"],"descriptionIncludes":["avionics"]} -> starter-list jobs in Costa Mesa whose title, department or description says avionics. If meta.complete is false and meta.next_board_cursor is a number, call again with the same filters and {"boardCursor": that number}. No company.

Tool call template

This tool declares no required parameters. Add optional parameters from the input schema as needed.

{
  "id": 1,
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "arguments": {},
    "name": "jobs_search_by_location"
  }
}

Input Schema

NameRequiredDescriptionDefault
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". "only" is a place signal and keeps remote jobs. "exclude" alone does not start a scan.
countriesNoOptional ISO-3166 alpha-2 codes, any-of, case-insensitive. Counts as a place signal. Example: ["US"]
locationsNoOptional, 0-50 strings, any-of. Place names, any-of. US state names and codes match both ways (Baltimore MD, MD, Maryland, FL, Florida). Metro aliases include NYC, SF, LA, DC, Tampa Bay, and Baltimore / BWI. "remote" also matches ATS remote flags. At least one of locations, countries or remote "only" is required. This tool has no company parameter. Example: ["Tampa"]
titleRegexNoOptional case-insensitive regular expression the title must match (max 200 characters, no nested quantifiers). Example: "^senior\\b"
boardCursorNoOptional index into the starter list, integer >= 0, default 0. Pass meta.next_board_cursor from the previous response, with the same place and keywords, to continue boards that call did not start. This is not the row offset.
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"]
titleIncludesNoOptional, 0-50 strings, any-of. Keep titles containing any of these whole words/phrases, case-insensitive. Title only. For a skill that may appear only in the posting, use descriptionIncludes instead. Example: ["engineer"]
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)
descriptionIncludesNoOptional, 0-50 strings, any-of. Whole words matched against the title, the department, or the scrubbed description, case-insensitive, any-of. Use this for a role or skill that may not be the job title ("avionics" matches an Avionics department, or Electrical Technician when the body says avionics). Do not also put the same word in titleIncludes. "RN" does not match "Registered Nurse". Greenhouse checks title and department on the lite list first. The row includes description_text only when includeDescription is true. Example: ["avionics"]

Output Schema

NameRequiredDescriptionDefault
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

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed2 schema fields changed
    • addedInput schema / properties / boardCursor
      Added value: +{
      +  "description": "Optional index into the starter list, integer >= 0, default 0. Pass meta.next_board_cursor from the previous response, with the same place and keywords, to continue boards that call did not start. This is not the row offset.",
      +  "maximum": 10000,
      +  "minimum": 0,
      +  "type": "integer"
      +}
    • changedInput schema / properties / descriptionIncludes / description
      Previous value: -"Optional, 0-50 strings, any-of. Whole words matched against the title OR the scrubbed description, case-insensitive, any-of. Use this for a role or skill that may not be the job title (\"avionics\" matches Electrical Technician when the body says avionics). Do not also put the same word in titleIncludes. \"RN\" does not match \"Registered Nurse\". Reads the description from the same board request. The row includes description_text only when includeDescription is true. Example: [\"avionics\"]"New value: +"Optional, 0-50 strings, any-of. Whole words matched against the title, the department, or the scrubbed description, case-insensitive, any-of. Use this for a role or skill that may not be the job title (\"avionics\" matches an Avionics department, or Electrical Technician when the body says avionics). Do not also put the same word in titleIncludes. \"RN\" does not match \"Registered Nurse\". Greenhouse checks title and department on the lite list first. The row includes description_text only when includeDescription is true. Example: [\"avionics\"]"
  2. Changed3 schema fields changed
    • addedInput schema / properties / descriptionIncludes
      Added value: +{
      +  "description": "Optional, 0-50 strings, any-of. Whole words matched against the title OR the scrubbed description, case-insensitive, any-of. Use this for a role or skill that may not be the job title (\"avionics\" matches Electrical Technician when the body says avionics). Do not also put the same word in titleIncludes. \"RN\" does not match \"Registered Nurse\". Reads the description from the same board request. The row includes description_text only when includeDescription is true. Example: [\"avionics\"]",
      +  "items": {
      +    "maxLength": 100,
      +    "minLength": 1,
      +    "type": "string"
      +  },
      +  "maxItems": 50,
      +  "type": "array"
      +}
    • changedInput schema / properties / locations / description
      Previous value: -"Optional, 0-50 strings, any-of. Place names, any-of. US state names and codes match both ways (Tampa, FL, Florida); NYC, SF, LA, DC, Tampa Bay and other US metro aliases match. \"remote\" also matches ATS remote flags. At least one of locations, countries or remote \"only\" is required. Example: [\"Tampa\"]"New value: +"Optional, 0-50 strings, any-of. Place names, any-of. US state names and codes match both ways (Baltimore MD, MD, Maryland, FL, Florida). Metro aliases include NYC, SF, LA, DC, Tampa Bay, and Baltimore / BWI. \"remote\" also matches ATS remote flags. At least one of locations, countries or remote \"only\" is required. This tool has no company parameter. Example: [\"Tampa\"]"
    • changedInput schema / properties / titleIncludes / description
      Previous value: -"Optional, 0-50 strings, any-of. Keep titles containing any of these whole words/phrases, case-insensitive. Example: [\"engineer\"]"New value: +"Optional, 0-50 strings, any-of. Keep titles containing any of these whole words/phrases, case-insensitive. Title only. For a skill that may appear only in the posting, use descriptionIncludes instead. Example: [\"engineer\"]"
  3. Added

TDQS

A4.8/5.0
Behavior5/5

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

Annotations already declare readOnly/openWorld/idempotent/non-destructive, but the description goes far beyond them: inputs leave the client, nothing is stored, a place signal is required or INVALID_INPUT is returned, retry rules for 5xx but not 403/429, 25-second wall clock, CPU and 300-request budgets, 200-row cap, partial results with stop_reason, and cursor semantics. The offset-vs-boardCursor distinction is also disclosed, and nothing 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.

Conciseness3/5

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

The WHAT/WHEN/WHEN NOT/BEHAVIOR/COST/RETURNS/PARAMETERS/EXAMPLE structure is disciplined and the behavioral detail is largely load-bearing for a tool with partial-result and budget behavior. However, the opening sentence is a paid-product advertisement rather than the tool's purpose, and the upsell to the Apify Actor/MCP endpoint is repeated several times across the description, which violates front-loading and wastes space.

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 13-parameter, budget-limited, paged search tool, the description covers the missing piece that matters most: when coverage is incomplete, how to resume with meta.next_board_cursor and when not to call again. Since an output schema exists, the extensive meta explanation is more than sufficient, and the required place-signal precondition is stated clearly.

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 the baseline is 3, but the description adds real meaning beyond the schema: US state names and codes expand both ways, metro aliases like NYC/SF/BWI are recognized, 'RN' does not match 'Registered Nurse', descriptionIncludes searches title/department/scrubbed body and triggers a second Greenhouse request only under stated conditions, and boardCursor is a starter-list index rather than a row offset. These are semantics an agent could not infer from the schema alone.

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 description states a specific verb and resource: a free search of a bundled 135-board starter list by place and role, explicitly 'Not every employer and not every company. No company name.' It also distinguishes itself from siblings by naming jobs_get_board, jobs_find_board, and jobs_search_companies, so an agent can route correctly without opening other schemas.

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 are explicit: call this immediately when the user gives a place and/or role but no company, do not ask for a company, do not call jobs_find_board or jobs_get_board first, and use the paid indexed search for radius/salary filters or employers outside the starter list. Concrete examples ('avionics jobs in Baltimore MD', 'remote RN jobs in PA') remove ambiguity.

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

Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.

Resources