MCP · worked examples
What a job postings MCP server can do: worked examples
The MCP server page lists every tool and its input schema. This page shows what agents actually do with them: the prompt you give, the tool-call sequence the agent runs, and the JSON that comes back at each step. Responses are abridged to the fields each step uses — full shapes are in the API reference.
Connect
Paste this into your client's server config, replacing the placeholder with your
own key. Endpoint https://mcp.reqbeat.com/mcp,
authenticated with the X-API-Key request header.
{
"mcpServers": {
"reqbeat": {
"url": "https://mcp.reqbeat.com/mcp",
"headers": { "X-API-Key": "YOUR_REQBEAT_API_KEY" }
}
}
}
No key yet? Get an API key. Free, no card.
Client setup, per connector
The server speaks streamable HTTP and authenticates with the
X-API-Key header, so it works in any MCP-capable client. The four
we see most:
Claude Code
One command, then every tool is available in the session:
claude mcp add --transport http reqbeat \
https://mcp.reqbeat.com/mcp \
--header "X-API-Key: $REQBEAT_API_KEY"
Claude Desktop
Claude Desktop's config launches local servers, so bridge the remote endpoint with
mcp-remote. Add this to claude_desktop_config.json
(Settings → Developer → Edit Config) and restart the app:
{
"mcpServers": {
"reqbeat": {
"command": "npx",
"args": [
"-y", "mcp-remote",
"https://mcp.reqbeat.com/mcp",
"--header", "X-API-Key: YOUR_REQBEAT_API_KEY"
]
}
}
}
Cursor
Cursor reads remote servers with custom headers directly. Put this in
.cursor/mcp.json in your project (or ~/.cursor/mcp.json
globally):
{
"mcpServers": {
"reqbeat": {
"url": "https://mcp.reqbeat.com/mcp",
"headers": { "X-API-Key": "YOUR_REQBEAT_API_KEY" }
}
}
}
A custom agent over the Anthropic SDK
For your own agent, connect with the official MCP SDK (the connection is
client-side, so the X-API-Key header works as-is) and hand the
discovered tools to the Anthropic SDK's tool runner. Python shown; the
TypeScript SDK has the same helpers:
# pip install anthropic[mcp]
import asyncio, os
from anthropic import AsyncAnthropic
from anthropic.lib.tools.mcp import async_mcp_tool
from mcp import ClientSession
from mcp.client.streamable_http import streamablehttp_client
client = AsyncAnthropic()
REQBEAT = "https://mcp.reqbeat.com/mcp"
HEADERS = {"X-API-Key": os.environ["REQBEAT_API_KEY"]}
async def main():
async with streamablehttp_client(REQBEAT, headers=HEADERS) as (read, write, _):
async with ClientSession(read, write) as mcp:
await mcp.initialize()
tools = (await mcp.list_tools()).tools
runner = client.beta.messages.tool_runner(
model="claude-opus-5",
max_tokens=16000,
tools=[async_mcp_tool(t, mcp) for t in tools],
messages=[{"role": "user", "content":
"Is braze.com hiring? If so, rank it by hiring pulse "
"and watch it for new postings."}],
)
async for message in runner:
print(message)
asyncio.run(main())
Example 1 — the core loop: from a domain to a webhook that fires on new postings
The sequence almost every workflow builds on. The agent resolves a company, gates it on whether it is hiring, reads its pulse, then saves a watch so new postings push to your endpoint — no polling afterwards.
The prompt:
"Is Braze hiring? If they are and hiring is picking up, watch them and push new postings to https://hooks.example.com/reqbeat."
Step 1 — resolve the company. find_company turns a domain or name into the company_id every other tool takes. Never billed.
→ find_company({"domain": "braze.com"})
{
"companies": [
{
"company_id": 5512,
"company_name": "Braze",
"company_domain": "braze.com",
"country_code": "US",
"coverage_status": "ats_direct_hit"
}
]
}
Step 2 — gate cheaply. is_hiring is the yes/no check before spending a richer call. A company with coverage_status: "no_ats_signal" is unknown, not quiet — don't score it as a negative.
→ is_hiring({"company_id": 5512})
{
"is_hiring": true,
"open_req_count": 48,
"coverage_status": "ats_direct_hit"
}
Step 3 — read the pulse. hiring_pulse answers "is hiring picking up": reqs opened in the last 30 days, velocity against the 30 before, direction, surge flag. A company still being crawled returns {"job_id": …, "status": "crawling"} — poll again later rather than reading it as "not hiring".
→ hiring_pulse({"company_id": 5512})
{
"new_roles_30d": 23,
"velocity": 1.4,
"direction": "up",
"is_surge": false,
"momentum": 5.1
}
Step 4 — register the delivery target. register_webhook is idempotent: the same URL twice returns the same id, so retries never leave two endpoints. The signing secret is returned once, on this call only.
→ register_webhook({"url": "https://hooks.example.com/reqbeat"})
{
"id": 42,
"url": "https://hooks.example.com/reqbeat",
"secret": "0f52c1…9be4"
}
Step 5 — save the watch. watch_company subscribes the company's hiring events to that endpoint. opened is the event to treat as a fresh trigger; reposted is a req that came back, not a new opening.
→ watch_company({
"company_id": 5512,
"event_types": ["opened"],
"webhook_endpoint_id": 42
})
{
"id": 311,
"company_id": 5512,
"event_types": ["opened"],
"webhook_endpoint_id": 42
}
What lands on your endpoint when Braze posts a new req — the same signed envelope documented on the webhook reference, abridged here. Verify X-Reqbeat-Signature before acting on it:
{
"envelope": "reqbeat.webhook.v1",
"watch_id": 311,
"webhook_endpoint_id": 42,
"events": [
{
"event_type": "opened",
"company_id": 5512,
"company_name": "Braze",
"req_key": "greenhouse:braze:7210045",
"title": "Senior Platform Software Engineer I",
"url": "https://boards.greenhouse.io/braze/jobs/7210045",
"observed_at": "2026-11-09T07:12:40+00:00"
}
]
}
Prefer pull over push? get_changes
is the same ledger as a replayable feed: events with event_seq greater
than your cursor, ascending, plus a next_cursor to resume from.
Example 2 — GTM engineer: qualify an account list
The prompt:
"Here are 40 target domains. Which should we work this week, and why?"
The agent runs the gate-then-rank loop per domain — the two cheap calls first, the richer one only for accounts that clear the gate:
for each domain:
→ find_company({"domain": domain}) // never billed
→ is_hiring({"company_id": id}) // never billed; gate
→ hiring_pulse({"company_id": id}) // rank on velocity,
// direction, is_surge
then, for the account you're about to work:
→ pre_action_brief({"company_id": id})
// one bounded round-trip: pulse + top open reqs (deduped
// across boards) + first-hire-by-function events + reposted,
// hard-to-fill reqs + ATS-vendor migrations
pre_action_brief
exists so the "write me an opener for this account" step doesn't take five calls.
Need the full req list instead of the brief's top slice?
get_open_reqs returns
every active req, deduped across boards, filterable by function and country.
The complete recipe — system prompt included — is at
the hiring-pulse agent recipe.
Example 3 — automation builder: wire hiring signals into outreach
The prompt:
"Find live senior data-engineer roles at product companies in Germany and the US. For each, draft an intro that references the actual posting."
find_qualified_reqs
collapses the whole ICP into one call — countries, title keywords and seniority
together, agencies and expired postings excluded by default:
→ find_qualified_reqs({
"criteria": {
"company": {"country": ["United States", "Germany"]},
"req": {"q": ["data engineer"], "seniority_level": ["senior"]}
}
})
{
"rows": [
{
"company_id": 5512,
"company_name": "Braze",
"req_key": "greenhouse:braze:7210112",
"title": "Senior Data Engineer",
"url": "https://boards.greenhouse.io/braze/jobs/7210112",
"seniority_level": "senior",
"skills": ["python", "airflow", "snowflake"]
}
],
"next_cursor": 184207
}
Each row names the company and carries the posting URL — enough to personalize
without another lookup. For free-text search across titles there's
search_jobs, and
get_role pulls one
role's detail by the company_id + req_key pair a search
row already carries. When an account converts, the agent reports it back — so your
outcome data accrues against the signals that produced it, visible only to your account:
→ write_outcome({
"company_id": 5512,
"outcome": "meeting_booked",
"observed_at": "2026-11-09T09:00:00Z",
"req_key": "greenhouse:braze:7210112"
})
{ "id": 87 }
Example 4 — agency: monitor clients' competitors
The prompt:
"Watch these five competitors of our client. Tell me when any of them starts or stops hiring for growth roles."
Same core loop, multiplied — resolve each name, save a watch for
opened and closed events. By name,
find_company returns up
to five candidates with a match_confidence, so the agent can pick the
exact-name match. The part that matters for a retainer:
list_watches reports
each watch's heartbeat, so a watch that is silent because nobody is hiring reads
differently from one whose endpoint is failing:
→ list_watches({})
{
"watches": [
{
"id": 311,
"company_id": 5512,
"event_types": ["opened", "closed"],
"webhook_endpoint_id": 42,
"status": "firing",
"last_fired_at": "2026-11-08T16:02:11Z",
"fires_last_7d": 9,
"fires_last_30d": 31,
"rate_limited": false
}
]
}
When the engagement ends, cancel_watch
frees the slot — it's idempotent, so cancelling twice succeeds twice. A free key
holds a limited number of watches at once; cancelling returns the slot.
Cost and correctness notes
find_company,is_hiring,list_watches,cancel_watchandwrite_outcomeare never billed.register_webhookis free; the watch that follows is what meters.who_is_hiring_forandfind_qualified_reqsbill per company or row returned ($0.10 each) — an empty result bills nothing.- Errors are explicit, never quietly partial: an unresolvable
geo, an unknownfunctionname, or an invalidevent_typeeach return an error that names the rule. Let the agent read them — the messages are written for it. - Pages are bounded. An oversized
limitis rejected rather than truncated — page through with thecursorinstead. - The corpus is LinkedIn-excluded (ATS tenants plus public job boards and aggregators) and freshness-floored; the method page states the sample and the known biases.
Related reading
The MCP server
Every tool, its input schema and the registry manifest — the same key as REST.
see the tools →Hiring-pulse agent recipe
Example 2 as a complete recipe: system prompt, config and cost notes.
read the recipe →Webhook reference
The full delivery envelope, the four event types and signature verification.
read the docs →