Skip to Content
ReferenceMCP tools

MCP tools

27 tools over stdio, mapping onto the CLI verbs one for one. 22 of them are free; the 5 that spend a model call say so in the description a client reads, so an agent knows the cost before it calls.

The server is a thin adapter and nothing more: every tool calls the same runners and the same Storage methods the CLI calls, and holds no logic of its own (ADR 0008). That is why the two surfaces cannot disagree about what set_status does.

Start it with karani mcp. Connecting a client has the configuration for Claude Code, Claude Desktop, Cursor and anything else that speaks stdio.

Finding work

The two tiers. ingest is free and qualify is not, which is the whole shape of the pipeline (ADR 0001).

ingest

Fetch postings from all sources, pre-filter, and store them.

Network-heavy: hits every configured ATS board and feed. Returns run statistics including per-source outcomes and drop reasons.

Takes no parameters.

sweep

Mark jobs not seen for days (default from settings) as closed.

ParameterTypeDefault
daysintegerunset

discover

Probe companies discovered on feed sources for ATS presence (Greenhouse/Lever/Ashby/Workable) and promote hits for future ingest runs. Network-bound; requires Postgres (no-op on the in-memory fallback).

ParameterTypeDefault
limitinteger10

qualify

Billed. Spends a model call.

LLM-qualify pending pre-filtered rows against the resume.

Billed per row. agent_mode=True runs the tool-using agent loop (OpenRouter only) — much more expensive; use on top candidates only.

ParameterTypeDefault
agent_modebooleanfalse
concurrencyinteger3
limitinteger20
modelstringunset
providerstringunset
resume_pathstringunset

Reviewing

What came in, and what to do about it today. next_actions is the one to reach for first in a conversation — it answers “what should I do on the job hunt today?” without the client having to assemble it from three other calls.

next_actions

Prioritized worklist for the daily loop, bucketed by required action:

  • review: qualified/maybe roles awaiting a verdict (fit + freshness ranked)
  • to_draft: verdict was apply but no draft exists yet
  • to_submit: drafts sitting in drafting/ready
  • follow_up: applied >= follow_up_days ago with no response

Call this first each session; it is the pipeline’s answer to “what should happen next”.

ParameterTypeDefault
follow_up_daysinteger7
review_limitinteger10

shortlist

Top qualified/maybe roles ranked by fit score, as structured rows.

Excludes roles already reacted to (except later).

ParameterTypeDefault
limitinteger20

digest

Render the top qualified roles as text, md, or html.

ParameterTypeDefault
formatstringmd
limitinteger20

get_job

Full detail for one job: qualification, gaps, state, and optionally the job description text.

ParameterTypeDefault
job_idintegerrequired
include_descriptionbooleanfalse

pipeline_stats

DB counts plus the application state-machine funnel.

Takes no parameters.

Building and sending

The pack, then the console that lays it out, then the write-back that records what you actually sent. karani never submits (ADR 0012), so there is deliberately no tool here that would.

draft

Billed. Spends a model call.

Build the full application pack for a job: cover letter + bullets

  • answers, an AI-voice humanizer pass, a complete tailored resume, and artifact uploads to object storage with presigned tweak-and- submit links. Moves the job to drafting. Billed (up to three LLM calls; KARANI_HUMANIZE / KARANI_TAILOR_RESUME toggle the extras).
ParameterTypeDefault
job_idintegerrequired
modelstringunset
output_pathstringunset
providerstringunset
resume_pathstringunset

submission_console

Build the submission console: one self-contained HTML file listing every pack waiting to be sent, with that job’s REAL application questions (read from the Greenhouse/Lever/Ashby public APIs), the answers, and presigned document links. Free - no LLM call. karani never submits: open the file, send each application yourself, then call mark_submitted.

ParameterTypeDefault
limitinteger50
output_pathstringunset
refresh_questionsbooleanfalse

mark_submitted

Record applications the USER sent (karani never sends them): status applied, the timestamp, and a snapshot of the artifact version that went out. This is what arms follow-ups and gives the funnel its labels. via: console | portal | email | referral.

ParameterTypeDefault
job_idsinteger[]required
notesstring“
viastringconsole
warm_pathbooleanunset

Tracking

The state machine. Moving an application to screen or interview through set_status fires an interview prep pack by itself (ADR 0024) — the tool call that looks like bookkeeping is the one that spends two model calls.

set_status

Set the application state: new, drafting, ready, applied, screen, interview, offer, rejected, declined, or ghosted. When marking applied, pass warm_path=true/false (referral or direct contact vs cold portal) — it feeds the warm-vs-cold split in funnel_stats.

ParameterTypeDefault
job_idintegerrequired
statusstringrequired
warm_pathbooleanunset

add_stage

Append an interview/application stage to the job’s stage log, e.g. recruiter_screen, hiring_manager, technical, onsite. After the stage, bank the questions actually asked via record_question — they compound into future prep packs.

ParameterTypeDefault
job_idintegerrequired
stagestringrequired
notesstring“

record_question

Bank a question actually asked in an interview for this job. Company-scoped: every future prep pack for this company recalls the bank, so preps get sharper with each interview.

ParameterTypeDefault
job_idintegerrequired
questionstringrequired
stagestring“

record_outcome

Record the final outcome: offer, rejection, ghosted, declined, or withdrew. Hard signal for future taste calibration.

ParameterTypeDefault
job_idintegerrequired
outcomestringrequired

record_verdict

Record your reaction to a suggestion: apply, shortlist, later, skip, or applied. Feeds the taste-calibration few-shot loop on future runs.

ParameterTypeDefault
job_idintegerrequired
verdictstringrequired

Preparing

For the conversation after the application.

prep

Billed. Spends a model call.

Interview prep pack for a job in the pipeline: a refreshed company dossier, likely questions derived from the qualifier’s gap analysis, STAR stories mined from the candidate’s own records (each traced back to the record it came from), derived comp research for the band, questions to ask grounded in company data, and warm-path openers. Also fires automatically when an application moves to screen or interview. Writes drafts/prep_<id>_<company>.md and uploads ATS-safe documents. Billed (two LLM calls).

ParameterTypeDefault
job_idintegerrequired
modelstringunset
providerstringunset
resume_pathstringunset
stagestringinterview

draft_followup

Billed. Spends a model call.

Draft a follow-up note for an application gone quiet, hooked on a specific fact from the company dossier. Karani drafts; the user sends. Writes drafts/followup_<id>_<company>.md. Billed (one LLM call).

ParameterTypeDefault
job_idintegerrequired
modelstringunset
providerstringunset

company_intel

Cached public-signal dossier for a company: background, engineering presence (GitHub), and warm-path candidates. TTL-refreshed (14 days); reused by prep, follow-up, and agent-mode qualification.

ParameterTypeDefault
companystringrequired
force_refreshbooleanfalse

warm_paths

Warm-path candidates at a company — engineers with a public presence (currently: public GitHub org members). Referrals and direct contact convert far better than cold portal applications; karani surfaces candidates, the user decides whom to contact.

ParameterTypeDefault
companystringrequired

Measuring

Conversion, segmented and interval-reported (ADR 0022).

funnel_stats

Conversion funnel over all applications: response, interview, and offer rates — overall and split by fit band, source, and qualify/draft prompt version. The measurement layer for positioning experiments.

Takes no parameters.

Memory

What karani retains between conversations. remember is the API for “I learned something about this company somewhere else”: every later qualification recalls it.

remember

Store a distilled fact in karani’s memory layer, e.g. a preference (“prefers infra roles over pure ML”), a company fact (“GitLab responds within a week”), or a strategy note (“data-platform angle beats causal-ML angle for infra roles”). kind: preference | company | outcome | strategy | question. Recalled automatically during qualification and on demand via recall.

ParameterTypeDefault
contentstringrequired
companystringunset
kindstringpreference

recall

Query karani’s memory layer. Returns the most relevant stored facts for a free-text query, optionally filtered by kind or scoped to a company (company scoping still includes global memories).

ParameterTypeDefault
querystringrequired
companystringunset
kindstringunset
limitinteger5

Pushing it somewhere

The other surfaces, driven from here.

notify_slack

Push the digest or the next-actions worklist to the configured Slack channel (SLACK_CHANNEL + SLACK_BOT_TOKEN). kind: digest | actions.

ParameterTypeDefault
kindstringdigest
limitinteger10

notion_sync

Mirror every tracked application (any job with a verdict or an application status) onto the Notion job-hunt board. Idempotent: pages are created once and patched thereafter. Requires NOTION_TOKEN and NOTION_DATABASE_ID (create the board with python -m ingestion.cli notion init &lt;parent_page_id>).

Takes no parameters.

autopilot

Billed. Spends a model call.

Run one autopilot pass: draft application packs for the top-fit qualified roles not yet reviewed and deliver each to Slack as a review card with Approve / Skip / I-applied buttons. Billed (one draft per candidate, capped by max_drafts, default 3; fit floor default 85). Karani never submits — the human does.

ParameterTypeDefault
max_draftsintegerunset
min_fitintegerunset
Last updated on