API DOCUMENTATION / MCP TOOLS
MCP tools
Every tool on the Headcount Labs MCP server, what it does, whether it uses jobs, and which call to make for common requests, tested against the live server.
Tools
The MCP server at https://api.headcountlabs.com/mcp has nine tools. Two of them, search_jobs and get_job, use jobs from your monthly plan; the others are free.
| Tool | Uses jobs | What it does | Example prompts |
|---|---|---|---|
search_docs | No | Answers a question about Headcount Labs (filters, limits, pricing, plans, MCP setup, errors) with the best-matching sections of the headcountlabs.com docs, each with its URL. Input: question (up to 500 characters) and limit (1 to 10, default 5). It is the one tool that works before you sign in. | “How do I filter Headcount Labs jobs by pay?” “What happens when I reach my monthly job limit?” |
search_jobs | Yes. Every job returned counts as one job. | Searches jobs with any /v1/jobs filter, passed in filters, plus limit (1 to 25, default 10), cursor and sort (relevance or updated). Each result has a usage object with jobs_used_this_call and jobs_remaining_this_month. For a large result set, pass deliver_file: true and max_jobs (1 to 5,000, default 1,000): the jobs are written to a JSONL file with a download link that works for one hour, and the result shows the first 25 jobs. If one search would return more than your confirmation level (25% of your monthly plan by default), the call stops with confirmation_required and your agent asks you first. | “Find remote data engineer jobs in Germany posted this week.” “Get every open nursing job in Texas as a file.” |
get_job | Yes. One job. | Returns one job by its job_id, with every linked posting and its source URLs. include_source_data: true adds each posting's source data. A merged job is followed to the job it merged into. | “Show me the full record for job 0b7cā¦, including every source posting.” |
count_jobs | No | Counts jobs that match the same filters as search_jobs. Use it to size a search before fetching it. | “How many software engineer jobs in Canada were posted since October 1?” |
list_fields | No | Lists the search_jobs filters and the job fields whose name or description contains your keywords (up to 20 words; none lists everything), with each one's type and a short description. | “Which filters can I use for pay and remote work?” |
read_file | No. The jobs were counted when the file was made. | Reads jobs from a file that search_jobs delivered, by file_id, offset and limit (1 to 100, default 25), and returns a fresh one-hour download link. Files last 24 hours. | “Show me jobs 100 to 200 from the file you just made.” |
get_usage | No | Reports your plan, the jobs used this month, your monthly job limit, unused jobs carried over, the jobs remaining, when the allowance resets, your confirmation level, and an upgrade link on the free plan. It works when the allowance is used up. | “How many Headcount Labs jobs do I have left this month?” |
set_confirmation_level | No | Sets the percent of your monthly jobs that one search may return before search_jobs asks you to confirm. Input: percent, a whole number from 0 to 100. The default is 25; 0 turns the question off. Agents change it only when you ask. | “Don't ask me before large searches any more.” “Ask me before any search that uses more than 10% of my plan.” |
set_overage | No | Turns overage on or off and sets its optional monthly limit. Inputs: enabled and monthlyLimitUsd (the most overage may cost in a month, in dollars; null clears it). With overage off (the default), searches stop at your monthly job limit; with it on, jobs past your plan are billed at your plan's overage rate per 1,000 jobs at month end, until the limit is reached. With no limit, overage has no ceiling. It needs a paid plan; on the free plan it returns an upgrade_url. Agents change it only when you ask. | “Turn on overage so my searches keep working past my plan.” “Don't let overage cost more than $25 a month.” |
Which tool to call
What a user might say, the call an agent should make, and the rule behind it. Every call below was run against the live MCP server on October 9, 2026: 36 of 36 returned the expected result. The calls that change billing or have no tool yet were not run. {{today-7}} means the date seven days ago, and {{prev.job_id}} a value from the previous call's result. The same key is at /docs/mcp-answer-key.json for agents and test harnesses.
| User says | Call | Why |
|---|---|---|
| “How many jobs do you have?” | | No filters counts every published job. |
| “How many nursing jobs are there in California?” | | state alone means a U.S. state, as a two-letter code. |
| “How many open jobs does Salesforce have?” | | company matches the employer name as text; active=true keeps jobs whose currentness is current. |
| “Find remote software engineer jobs.” | | Remote is work_arrangement=remote, not a word search. title_advanced catches the common title variants. |
| “Show me senior software engineer jobs.” | | title matches the words as one phrase in order, so title="senior software engineer" misses "Software Engineer, Senior". Use title_advanced. |
| “What jobs is Salesforce hiring for?” | | company is a case-insensitive contains match on the employer name. |
| “Jobs posted in Texas in the last week.” | | posted_since is the date the source published the job; a plain date works. |
| “Data analyst jobs paying at least $100k a year.” | | pay_min is yearly; hourly pay is converted at 2,080 hours. |
| “Jobs in Toronto.” | | Add country for a city outside the U.S. CA as a country is Canada. |
| “Jobs in Ontario, Canada.” | | A non-U.S. state or province needs country too; state=ON alone would mean a U.S. state. |
| “Part-time jobs in New York City.” | | employment_type is an exact value such as full_time or part_time. |
| “Hybrid product manager roles.” | | work_arrangement is remote, hybrid or in_person. |
| “Jobs that mention Kubernetes.” | | description searches the job text; q searches title or description. |
| “Jobs that need Python but not Java.” | | description_advanced takes AND, OR, NOT and parentheses. |
| “Anything about machine learning.” | | q is a phrase in the title or description, ranked by relevance. |
| “Only show jobs that are still open.” | | currentness=current (or active=true) keeps jobs the latest read still found. |
| “Leave out stale jobs.” | | stale=false filters stale jobs out. |
| “Jobs from Greenhouse boards only.” | | source is the vendor name in lower case. |
| “Marketing jobs that list a salary.” | | has_pay=true keeps jobs with a posting that publishes pay. |
| “Only jobs where I can still apply.” | | application_check is available, closed, broken or inconclusive; available means an application could still be started. |
| “How many jobs have a broken application link?” | | Expect 0. A broken or closed apply check takes that posting out of the current set, so a job with no other current posting is withdrawn and never reaches the public data. A count above 0 would mean withdrawn jobs are leaking into the public set. To find jobs whose apply link is still open, use application_check "available". |
| “Jobs that were taken down.” | | posting_status=no_longer_listed means a complete read of the source no longer found the posting. |
| “What changed since yesterday?” | | updated_since with sort=updated is the incremental pull. |
| “Show me the next page.” | | Repeat the same filters with the cursor from the last result. |
| “Tell me everything about that job.” | | get_job returns one job with every linked posting and the full description. |
| “Show me the raw source data for that job.” | | include_source_data adds each posting's source fields. |
| “Give me the full descriptions, not snippets.” | | Descriptions are cut to 400 characters unless descriptions=full. |
| “Export the first 200 nurse jobs in Ohio as a file.” | | For more than about 100 jobs use deliver_file with max_jobs instead of paging 25 at a time. |
| “Read the next 25 jobs from that file.” | | read_file pages through a delivered file for free for 24 hours. |
| “How many jobs do I have left this month?” | | get_usage is free and works even when the allowance is used up. |
| “How many API requests have I used?” | | The same call reports requests used and remaining. |
| “What filters are there for pay?” | | list_fields is free; pass keywords to narrow it. |
| “What happens when I go over my plan?” | | Questions about plans, pricing, limits and setup go to search_docs, which is free. |
| “How do I connect Headcount Labs to Claude?” | | Setup questions go to search_docs. |
| “Stop asking me before big searches.” | | Only when the user asks. 0 turns the question off; the runner puts it back to 25. |
| “Turn on overage.” | | Only when the user asks. It changes billing, so the runner does not call it; on the free plan it returns an upgrade_url. |
| “Don't let overage cost more than $25 a month.” | | monthlyLimitUsd caps overage dollars a month; null clears it, and leaving it out keeps the current limit. Only when the user asks; the runner does not call it. |
| “Show Salesforce jobs with the company details.” | | include=company adds the linked company record to each job. |
| “What's the average salary for nurses?” | No tool yet | No MCP tool answers this yet. Say so; market statistics are coming to paid plans. Do not average a sample of search results and present it as the market figure. |
| “Look up Salesforce's company record.” | No tool yet | The MCP has no company tool yet. The REST API has GET /v1/companies; search_jobs with include=company adds the company record to each job. |
Common mistakes
- Filters go inside
filters:{"filters": {"title": "nurse"}}, not{"title": "nurse"}. There is noqueryfilter; the keyword filter isq.list_fields(free) lists every filter name. titlematches the words as one phrase in order, sosenior software engineermisses “Software Engineer, Senior”. Usetitle_advancedwith AND, OR and NOT.- Remote work is
work_arrangement: "remote"(or hybrid, in_person), not a word search. stateon its own is a U.S. state. For a province or another country's region, addcountry:{"state": "ON", "country": "CA"}.- For more than about 100 jobs, use
deliver_file: truewithmax_jobs, thenread_file, instead of paging 25 at a time. - Size a search with
count_jobsfirst; it uses no jobs.
How jobs are counted
Every job a tool returns counts as one job from your plan, including a job you fetched before. The usage object on each search_jobs and get_job result shows jobs_used_this_call and jobs_remaining_this_month. The API and the MCP server share one monthly allowance; see rate limits and job credits.
Confirmation before large searches
One search is the first search_jobs call plus every call that passes its next_cursor, or one file delivery. When the next page would take that search past your confirmation level, the call returns an error with http_status 409 and code confirmation_required, and uses no jobs. Your agent should ask you, then repeat the call with confirmed: true. The level belongs to your account, not to one key.
Sign-in and access
MCP clients sign in with OAuth in your browser. The access token lasts one hour and the client refreshes it with a 30-day refresh token. The token can read jobs only: it works on /mcp and /v1/jobs routes. Revoke a connection by deleting its key on api.headcountlabs.com/data/keys. Setup steps for each client are on the MCP page.
Errors
A failed tool call returns isError: true with http_status, request_id and the API's error object; a 429 also carries retry_after. Codes the MCP server adds: confirmation_required (409), file_not_found (404, the file expired or belongs to another account) and invalid_request (400, for example a bad filter or cursor). A search_jobs, count_jobs or get_job call that runs past 10 seconds returns http_status 504 with code query_timeout and uses no jobs; add a state, city, source or company and call again. All API codes are listed under errors.