hyreflow docshyreflow docsDocumentation

MCP Reference

The tools, playbooks, billing and recording behavior behind an MCP connection.

What a connected agent sees, once setup is done. The server speaks the 2024-11-05, 2025-03-26, 2025-06-18 and 2025-11-25 revisions of the protocol.

Tools

  • hyreflow_tools_search: find tools by intent ("find software engineers", "verify emails"). The usual entry point. Names a matching recipe in its recipes field.

  • hyreflow_tools_describe: input contract and exact credit cost before running. Argument-priced and surcharged methods quote a worst case (credits_max, surcharge included), not a base price. Also reports a side_effect flag per method, so an agent can tell a reversible lookup from a write to your ATS.

  • hyreflow_tools_execute: run it. Waterfall sourcing like people search runs exactly as the CLI does it: house provider order, dedup, BYOK skips. An enrichment waterfall (email_enrichment, personal_email, linkedin_profile, phone_enrichment) also takes rows (up to 100 row objects) instead of payload to enrich many people in one call: the chain runs stage by stage and a provider that accepts a batch (FullEnrich) gets one job for every pending row, billed per row. rows is exclusive with payload and method. A step that is still running when the poll budget ends reports still_enriching with job_id and a resume object (tool, method, id_arg), and ends that row's chain there — no further provider runs for it. The job settles on its own server-side and bills once when it finishes; resume it sooner with a poll (free while the job runs; a finished job bills only the rows it revealed, once) rather than resending the row, which would start and bill a second job. A multi-row call also lands its rows in a dataset (_meta.dataset_id) — read them with hyreflow_dataset_read or hand the whole file over with hyreflow_dataset_export; a still_enriching row fills in there on its own once its job settles, with no re-poll needed just to complete the dataset. If the whole call comes back with nothing at all (a connector timeout, a dropped connection), resend the identical rows — within ~15 minutes it replays the first call's dataset for free (_meta.replayed, charged: 0) instead of billing a second run:

    {"tool":"email_enrichment","rows":[{"first_name":"Jane","last_name":"Doe","company_domain":"acme.example.com"}]}

    Pass those arguments to hyreflow_tools_execute. Use personal_email instead for candidates, but only when the user explicitly asked for personal emails. A bare "enrich" is ambiguous: ask which channel, or for screening/context (not contact details) use linkedin_profile instead.

    {"tool": "<resume.tool>", "method": "<resume.method>", "payload": {"<resume.id_arg>": "<job_id>"}}
  • hyreflow_workflows_list / hyreflow_workflow_run / hyreflow_workflow_runs: list this workspace's saved workflows, run one by the name or id that list returns, poll the run id it gives back. To drive it from a prompt:

    Run my "<workflow name>" workflow through hyreflow and tell me when it finishes, with the total credits spent.
  • hyreflow_monitor_save / hyreflow_monitors_list / hyreflow_monitor_items: monitors. A monitor checks a source on a schedule (daily at 09:00 in the workspace's time zone by default, at most hourly) and records the items it finds; its type says what it watches, and the save tool's description lists the types and the config each takes. Today that's company_jobs, new jobs on a company's careers page. Monitors are turned on per workspace: without them these three tools aren't listed. The save creates one from a type and config, or changes one by its monitor_id: status: "paused" stops its checks, "active" resumes them, check_now: true runs one within about 5 minutes (checks run at most once an hour). Its first check records what's already there as the baseline; every later check reports the new items. A new config replaces the old one whole, and any change clears the items found so far and takes a new baseline. The list shows each monitor's last check and how many new items it found, and the items tool returns the items, newest first, with since for only the recent ones. Each completed check costs a run fee plus credits for each new item (items seen before are free, and a failed check costs nothing); the save returns the price and the run fees a month. There is no delete tool: delete a monitor on the dashboard's Monitors page, or with the API (DELETE /api/v2/monitors/{id}).

    Watch acme.com's careers page for new sales jobs through hyreflow and tell me what it finds each week.
  • hyreflow_enrich_run: generic ordered, per-column enrichment over rows, or over a whole dataset by passing its ds_ id as input (a search's results, say) so the rows are not re-sent. Its steps execute per row; use hyreflow_tools_execute with an enrichment waterfall plus rows when you want provider-level batching. The call waits about 20 seconds: a larger run comes back with _meta.status: "running" and a run_id, and calling hyreflow_enrich_run again with just that run_id (free) returns its state until it reads completed. While it runs, _meta.progress counts rows done of the rows in range; once complete, the poll carries the same summary (per-provider hit counts) and credits_charged that a run finishing inside the wait returns — except a run the service resumed after a restart, which carries its rows but no summary. Re-sending an identical run within 15 minutes returns the first one at no charge. It polls each async step against a short in-request budget; a step still running when that budget ends comes back still_enriching with its job_id. Fetch that row later with hyreflow_enrich_job {provider, job_id}, which returns the same settled shape as GET /enrich/jobs/{provider}/{job_id} (status pending/settled/failed/expired, plus charged, email, result once settled) — free while pending, billed once on the poll that finds it settled.

  • hyreflow_shortlist: bulk-screen candidates against a job description, ranked with a tier and per-category scores. Pass candidates (for example the rows a CRM or ATS search returned) or input (a ds_ dataset id). The question set is generated once per job description and reused. The call waits about 20 seconds: a finished screen returns the top 25, with every ranked row in _meta.dataset_id; an unfinished one (always the first screen of a new job description) returns a run_id to poll by calling hyreflow_shortlist again with just that id. Polling is free, and re-sending an identical screen within 15 minutes returns the first one at no charge. dry_run: true quotes the cost first.

  • hyreflow_billing_balance: check spend.

  • hyreflow_onet_lookup: job title → O*NET-SOC codes. Free, and needed before job-openings discovery, which takes codes rather than titles. "Head of Talent Acquisition" resolves by dropping the seniority prefix; each result carries the official title and description so a loose match can be checked.

  • hyreflow_extract_image: puts candidate profile photos (a row's photo_url, or a raw AI Ark row's profile.picture.source; AI Ark or LinkedIn) into a hyreflow artifact page, which can't load images from other sites. Pass a dataset_id (up to 500 photos, read by the engine) or up to 100 links. Returns a link that's good for 15 minutes: post the finished page to it and it comes back with the photos inside. Expired or unreachable links come back under skipped. Free.

  • hyreflow_feedback: send feedback or a bug report, returns the filed issue's URL. Free. The session is attached so we can see the run that prompted it. Your client will ask before sending: it reaches real people.

  • hyreflow_knowledge_index, hyreflow_knowledge_search, hyreflow_knowledge_read: read your workspace's second brain. The index lists every note without its text, search takes a web-search style query ("quoted phrase", or, -exclusion), and read returns one note by slug (view: "body" for the text, "full" to add its data, sources and links). Read-only and free.

  • hyreflow_knowledge_write: create a note, or change one by slug. Only the fields you send change (title, body, status, folder, tags), and a note keeps its sources. A new note takes its slug from its title, and a slug already in use is refused rather than replaced. status: "archived" takes a note out of search. Any member can write, the change is live for the whole workspace, and there is no undo, so your client asks before each call. Free.

  • hyreflow_knowledge_import: add text files from your own computer to the second brain as draft notes in the Imported folder, one per file (up to 50 per call). Each file has a name and its content, and may have a kind (icp, persona, offer, pitch, proof or other) and up to 20 tags. An empty file is skipped, a body over 64 KB is cut and marked truncated, a file already imported with the same name and text is skipped (so resending adds nothing), and an existing note is left as it is: a slug in use gets a numeric suffix. Your assistant reads the files itself and sends their text, see Second brain. Free.

  • hyreflow_onboarding: the first-run flow behind "Run hyreflow onboarding for me". The default step: "start" returns the onboarding instructions and moves your setup page on. Your assistant calls it again with step: "progress" and a short note while it works, and step: "completed" at the end. Repeat calls are harmless. When your second brain is ready, your assistant uses it to suggest your first search. Free.

Every result reports the credits it charged in _meta.

Rows still being fetched

A still_enriching row is not a miss: its email is still being fetched and usually arrives within one to two minutes, so it does not yet mean "no email found". hyreflow_tools_execute, hyreflow_enrich_run and hyreflow_dataset_read results say so in _meta:

  • pending: how many rows in this response are still being fetched. 0 does not rule out pending rows on another dataset page. It is null when the call can't know whether they have landed since (for example a later poll of a finished run), so read the dataset instead.
  • pending_jobs: the open jobs, when the call has them.
  • poll_after_s: how long to wait before checking again (20 seconds).
  • instruction: the exact steps to follow, written for the assistant.
  • final: true once nothing is pending and every row has been seen, which means a fresh call's rows, a read of the whole dataset, or a finished run that left nothing pending. One page of a longer dataset, or a run still going, never carries it.

Check again every poll_after_s seconds with hyreflow_dataset_read on _meta.dataset_id, with hyreflow_enrich_job for each job, or, for a run still going, with hyreflow_enrich_run and only its run_id. All three are free. For a dataset that fits in one read, report the final count only when _meta.final is true. For a larger dataset, follow next_offset until has_more is false and check every page; a page with pending: 0 is not a stop signal. Once the run has completed, recheck pages with pending or unstamped rows until all rows have a final status. If the assistant stops early, it should say how many rows are still pending. Resending a row starts and bills a second job.

Spend confirmation

The server enforces a pre-spend check on hyreflow_tools_execute, hyreflow_enrich_run and hyreflow_shortlist. When a call's estimate exceeds the confirmation threshold — 50 credits, or a quarter of what the workspace has left, whichever is lower — nothing runs and nothing is charged. The lower bound is the one that matters on a small balance: a 30-credit batch is rounding error on a full account and more than half of a nearly-empty one, and it is the second case that needs asking. threshold_basis says which bound applied. For an enrichment the estimate is the typical cost — each provider in a waterfall weighted by how often it actually hits — with the worst case beside it as total_max_credits; a chain with too little history to say is gated on its worst case. The result is a structured confirmation_required object, also mirrored in _meta, with the estimate, the current balance and a short-lived token:

{
  "confirmation_required": true,
  "cost_estimate": {"credits": 38.0, "estimated_usd": 3.8, "tool": "personal_email", "rows": 10},
  "current_balance": 120.0,
  "balance_after": 82.0,
  "confirm_token": "cfm_...",
  "expires_in_s": 600
}

The agent shows the user the cost and asks for approval, then repeats the same call with approved_credits set to the number of credits the user approved. The call runs when its estimate is at or under that number and the engine holds an open quote for the exact same arguments, made for the same workspace member. A quote is single-use and expires after ten minutes, so a changed payload, an expired quote or a second resend gets a confirmation_required with no token instead of running; the next step is a call without approved_credits, which is quoted afresh (see below). The approved figure bounds the estimate checked on the retry, so an estimate that moves a little between the quote and the retry still runs within it. It is not a spending ceiling for the run itself: an enrichment can still bill up to its worst case, total_max_credits.

Repeating the identical call with confirm_token set to the token also works. The token is bound to the workspace, the exact arguments and the quoted price, and expires after ten minutes: a changed payload, a different price or an expired token returns a fresh confirmation_required instead of running. Either way, one confirmation_required buys one run. Calls at or under the threshold, dry_run calls and calls served by your own provider key (BYOK) flow through without the extra round trip.

A search quotes what it can actually spend: the pages the ask actually needs — ceil(limit / page_size) per source, since a limit above one vendor page forces paging to fill the quota. coverage: max is quoted for every source it visits, each paged only that far. The quote then becomes that search's spend cap for the rest of the call, whether or not it triggered a confirmation_required — if paging further would cost more than the quote, it returns the rows it has and marks the step estimate_cap rather than billing past it.

Three things the check does not hold: a saved workflow started with hyreflow_workflow_run, a job whose price is only known once the provider answers (an async scrape that bills per delivered record), and a monitor's scheduled checks, which bill on their own schedule after hyreflow_monitor_save. None is held by a spend cap unless the workspace has one (set on the billing page); a monitor's checks are held by the workspace's cap only, never a member's own. So watch _meta.credits_charged on those paths. An approval is single-use either way. Resending a call that already ran, with approved_credits or with a still-valid confirm_token from before the run, gets a confirmation_required that carries no token and opens no new quote, however many times it is resent. Running it again takes a call without either, whose new quote the user approves. The exception is an identical multi-row rows batch resent within about 15 minutes: it returns the stored dataset (_meta.replayed) at no charge, which is how a client checks on a batch it started. An expired or mismatched token is treated as a new ask: it gets a fresh quote and token, which the user approves again.

Every paid result also carries _meta.budget_warning when the run left the balance under 50 credits or consumed half or more of what was available, so the client sees a low-balance signal inline rather than after the next call fails.

Tools that only read are marked read-only, so a client that groups tools by permission can auto-approve the safe set: catalog search, playbook reading, run status, balance. Anything that spends credits or writes to a connected system stays outside that group and keeps asking: hyreflow_tools_execute, hyreflow_enrich_run, hyreflow_shortlist, any workflow run, and hyreflow_monitor_save, whose monitor bills every check it runs.

The playbooks come with it

An MCP client installs nothing, so the agent skills are served over the connection instead, in full: the recruiting playbook, a playbook per provider covering access rules, payload shapes and cost traps, the pipeline recipes, and the sub-agent prompts.

Reading a provider's playbook before executing that provider's tool is the difference between a call that works and one that burns credits on a malformed payload. Three things point at the right one: hyreflow_tools_search names a recipe, hyreflow_tools_describe names a provider playbook, and every hyreflow_tools_execute result carries the same pointer in _meta.playbook.

Connecting also hands the agent the routing table: the index mapping a task ("a job description → a shortlist", "a company just raised") to the document that covers it, so it knows which playbook to open before reading anything.

They arrive two ways, and every client supports at least one:

  • as MCP resources, addressed hyreflow://skills/<skill>/<path>: clients that show resources let you attach one to a conversation directly.
  • as tools: hyreflow_skills_list (every skill and document), hyreflow_skill_read (one document in full: a skill name alone returns its SKILL.md, or add a path like provider-playbooks/apollo.md), hyreflow_skill_search (find a document by term; searching a provider name is the fastest route to its playbook).

Your own skills

Skills your workspace writes itself (Custom skills) come over the same connection. The agent is told to check them at the start of a task and follow any that fit:

  • hyreflow_custom_skills_list: your personal skills and the team's skills, with a name and description each.
  • hyreflow_custom_skill_read: one skill's files at its live version, plus its version history. Pass version to read another one, such as your own draft still waiting for approval.
  • hyreflow_custom_skill_save: create a skill (scope personal or org) or, with skill_id, save a new version. Ask your agent to "save this as a skill" and it uses this. A team version waits for the workspace owner, who approves it on the dashboard's Skills page. There is no approve tool.

The two read tools are marked read-only, so a client can run them without asking. A save isn't, so a client asks before running it.

Billing

Tool calls bill identically on every surface: MCP, CLI, or API. A connected client counts as one session until it goes 24 hours without a charge. Its next call then starts a new session, so a per-session spend cap covers each stretch of work, and every charge lands on the approved workspace's balance. A connection inherits your workspace's default per-session cap if you have set one on the billing page; there is no cap otherwise, because a limit you did not choose is one you cannot raise from inside the client. With a cap set, paid calls stop with session spend limit reached once it is used up, until a reconnect or 24 idle hours start a fresh session. See pricing.

Run recording

A run trace records Hyreflow tool inputs and outputs, provider, timing, outcome, and client information when available, grouped per connection within your workspace. The tools that spend credits require a user_prompt: the request that drove the call, which your agent sends so a trace reads as your ask followed by the tools it drove. Your surrounding conversation is not captured. Traces carry workspace and user identifiers and account email for support attribution. Recognized contact fields and recognizable email addresses, profile links, and phone numbers are filtered from trace payloads; free-form text is not fully anonymized. Recording never changes results or billing.

Recording is on by default. A workspace can also be set to always record or never record, and where it is set it takes precedence over anything a client sends. Ask us what your workspace is set to, or to change it.

A client that lets you set request headers can send X-hyreflow-Telemetry: 0, honored unless your workspace is pinned. In Claude Code, add it when you connect:

claude mcp add --transport http hyreflow https://recruit.hyreflow.ai/api/v2/mcp \
  --header "X-hyreflow-Telemetry: 0"