MCP tools

Hiring-demand signals, callable directly from your agent. Every tool below is read from the running server, so this page never documents a call the server does not serve.

Read July 30, 2026 at 12:01 UTC · Refreshed every 3 hours

Connect

Reqbeat Hiring Signals (com.reqbeat/hiring-signals v1.0.0) is a remote MCP server over streamable HTTP. Paste this into your client's server config, replacing the placeholder with your own key:

{
  "url": "https://mcp.reqbeat.com/mcp",
  "headers": {
    "X-API-Key": "YOUR_REQBEAT_API_KEY"
  }
}

Endpoint https://mcp.reqbeat.com/mcp, authenticated with the X-API-Key request header.

10 tools

is_hiring

WHEN an agent already holds a company and needs to qualify it -- the cheap gate before spending a richer call. ATS/board-only and freshness-floored. Takes the integer `company_id` from an earlier result, not a company name or domain. company_id=1234 -> is_hiring true, open_req_count 7, coverage_status "ats_direct_hit". company_id=5678 -> is_hiring false with coverage_status "no_ats_signal" -- that company has no ATS coverage yet, which is not evidence it is quiet, so do not score it as a negative. No key yet? Pass `plane_api_key` as an empty string and the call answers with a signup link instead of an auth error. To find companies in the first place, use `who_is_hiring_for`.

get_open_reqs

The company's current active reqs, deduped across boards -- ATS/board-only, freshness-floored. `function` must be a function id (as seen in prior results); a plain role name like 'engineering' is rejected with an explicit error rather than an empty result. `limit` is bounded: an oversized page is rejected rather than truncated.

hiring_pulse

A company's hiring velocity/direction/momentum in one call -- dual-metered via `max_age` (seconds). Cold returns `{job_id, status: "crawling"}` instead of a synchronous body, same as the REST route.

who_is_hiring_for

WHEN an agent needs to FIND the companies worth working -- the sourcing step, before it knows which companies exist. Reverse who's-hiring-for {role, geo} search: companies with active reqs matching `role`/`geo`/`since`, deduped by company, keyset-paginated via `cursor`. `role` is free text matched against the posting title, not an id. `geo` is resolved to a stored country before matching; an unresolvable one is an explicit error, never a quietly partial page. `limit` is bounded -- page through the full set with `cursor` instead of raising it. Billed per company returned (~0.10 USD each) -- an empty result bills nothing. role="backend engineer", geo="USA" -> the companies with matching active reqs, each with its pulse and its matched reqs. geo="Atlantis" -> an explicit unresolvable-country error rather than an empty page. No key yet? On the hosted HTTP endpoint the first calls are free: pass `plane_api_key` as an empty string and the search runs on a shared demo credential -- a smaller page, billed to nobody -- until a per-IP limit is reached, after which the answer becomes a signup link whose minted key finishes this exact search. On any other transport a blank key answers with that signup link straight away. Already holding a company_id and only need a yes/no? Use `is_hiring`.

search_jobs

Flat, role-granular job search -- the individual open roles across companies matching `role` (function) / `geo` (country) / `since`, one row per logical req (each with its own `company_id` + `req_key`), ATS-only + freshness-floored. Keyset-paginated via the opaque `cursor` (a prior call's `next_cursor`). Use `who_is_hiring_for` for the company-granular reverse view. `role` must be a function id (as seen in prior results); a plain role name like 'engineering' is rejected with an explicit error rather than an empty result. `limit` is bounded: an oversized page is rejected rather than truncated, so page through the full set with `cursor` instead of raising `limit`.

pre_action_brief

The motion atoms + history primitives pre-joined into one bounded, compact call -- dual-metered via `max_age`. Cold returns `{job_id, status: "crawling"}`, same as the REST route.

get_changes

The `since=cursor` diff feed -- ledger events with `event_seq > since`, plus a `next_cursor`. Meters one `change` unit per event returned, independent of poll count. A free-tier caller is freshness-floored, the same as every other free-tier read. `limit` is bounded: an oversized page is rejected rather than truncated, so replay with `next_cursor` instead of raising `limit`.

register_webhook

Register the delivery target a watch fires to, and get back the `webhook_endpoint_id` `watch_company` needs -- call this first if you do not already hold one. Idempotent: registering the same `url` twice returns the same id, so retrying is safe and never leaves you with two endpoints. `secret` is optional; supply one to verify the `X-Plane-Signature` on delivered payloads, omit it and one is generated (it is never returned). Registration itself is free -- the `watch_company` call that follows is what bills. Plane session only: `webhook_endpoints` is plane-owned and this tool reads no corpus table.

watch_company

Subscribe to a company's hiring events on a registered webhook -- `webhook_endpoint_id` must belong to the same customer as the authenticated key. Meters one `watch` unit.

write_outcome

Write back a conversion outcome for `company_id` -- the label-flywheel substrate. Appends to `outcome_labels` scoped to the caller's own customer. Plane session only: `outcome_labels` is plane-owned (Phase 1 dropped its one foreign key into the corpus) and this tool reads no corpus table.