Skip to main content
Glama

FreeApply

FreeApply MCP server on Glama Listed on mcpservers.org

Free AI job applications that run on your computer. FreeApply finds jobs that fit your settings, applies through the AI app you already use, tracks every application in a local dashboard and checks Gmail for employer replies. Any role, any field.

Website: https://www.mybotsai.com · Install: https://www.mybotsai.com/install/ · Downloads: https://www.mybotsai.com/appserver/ · Release notes: release-notes/ · Source: https://github.com/FreeApply/freeapply

Current version: 1.0.5 (notes). The app and its legal documents share one version number.

What it does

  • Finds jobs that fit: roles, pay floor and locations from your settings, on the job sites you choose. Duplicates and reposts it has already tracked are skipped.

  • Applies for you on employer sites and job boards with your real details, your résumé and answers you saved once, at a measured pace.

  • Never invents experience. Cover letters and answers are checked against your résumé and settings before they are used.

  • Knows when to stop. CAPTCHAs, new accounts, passwords and questions your settings don't answer go to the Issues tab for you.

  • Tracks everything in a dashboard at http://127.0.0.1:7878, reachable only from your computer.

  • Watches for replies: with the Gmail app password you connect in setup, new employer emails show up in the dashboard within about 15 minutes, and your AI app sorts them every 4 hours by default (the Gmail connector works too).

  • Keeps going on its own once setup is done, while your AI app is open; Start and Stop are at the top of the dashboard, with what it's working on right now.

Related MCP server: cv-job-assistant

Install

App

How

Claude Desktop

Download freeapply.mcpb and double-click it, or drag it into Settings → Extensions. Nothing else to install.

Claude Code, Cursor, VS Code, Windsurf

Windows: irm https://www.mybotsai.com/appserver/install.ps1 | iexmacOS and Linux: curl -fsSL https://www.mybotsai.com/appserver/install.sh | bashNeeds Node.js 22.13 or newer. The installer checks the package's signature, then asks before adding FreeApply to each app it finds.

Claude Code, from this repository

/plugin marketplace add FreeApply/freeapply, then /plugin install freeapply@freeapply

Any other MCP app

Unpack freeapply.mcpb (it is a ZIP file) and add a stdio server that runs node /path/to/freeapply/src/main.js.

To update, install the new version the same way. To uninstall, see https://www.mybotsai.com/install/#uninstall. Your data in ~/.freeapply stays until you delete that folder.

First run

  1. Restart your AI app and say "Set up FreeApply". The dashboard opens.

  2. Read and accept the Terms of Service and Privacy Policy there yourself (18+). Until you do, every agent tool except freeapply_status and freeapply_open_dashboard refuses to run, and the agent can never accept for you.

  3. Fill in Settings: résumé (PDF, DOCX, TXT or MD), name and email, desired roles, minimum pay, locations, work authorization and the job sites you use. The agent applies nowhere until these are filled.

  4. Sign in to your job sites in the browser your AI app uses, then say "Find me jobs and apply".

With a Gmail connector, setup also schedules the reply check, which stars replies, labels them, or both (your choice in Settings).

Guarantees

  • Facts about you come only from your résumé, your settings and what you tell the agent. It never invents experience.

  • It never types passwords, creates accounts or solves CAPTCHAs. Those jobs are flagged for you.

  • Signed workflow. The procedures, server instructions and hard limits ship in agent/workflow.signed.json, signed with our release key. Any edit fails verification and locks the tools until the official copy is restored. Pacing, duplicate checks, the pay floor and the truthfulness check are enforced in the tool code, not just asked of the AI.

  • Your data stays on your computer, except what your data-sharing choices send. The dashboard accepts only local requests that carry its own header.

Data sharing

Choice

United States

Everywhere else, or with Global Privacy Control

Anonymous usage statistics

On by default, one-click opt-out

Opt-in

Job-market data (no name or contact details; sold only as totals covering 5+ installations)

On by default, one-click opt-out

Opt-in

Recruiter Talent Pool (contact details and résumé, sold to recruiters)

Opt-in

Opt-in

Product update emails

Opt-in

Opt-in

The region comes from your profile country, otherwise your computer's language and time zone; unknown counts as outside the US. In Settings → Data sharing you can preview exactly what is sent, sync now, and delete everything already shared. Details: Privacy Policy.

The dashboard shows one card labeled "Sponsored", chosen on your computer from a signed pack. No ad scripts, no trackers, and no data is sent to show it.

Dashboard

Overview, Applications, Replies, Issues and Settings, with the Terms, Privacy Policy, Disclosures and Recruiter Terms linked in the footer. The Needs you tab collects what needs you, in plain words:

  • Questions: what a form asked that your settings don't answer, each as a simple question you answer by typing, from a dropdown or by picking options. A question several jobs ask is shown once, and one answer goes to all of them; questions you already answered aren't asked again. The jobs then go back in the queue.

  • Accounts to make: one card per sign-up page, however many jobs wait on that account, with its link and a FreeApply Autofill bookmarklet that fills your name, email, phone and location on sign-up pages. Passwords stay with your browser or password manager.

  • Stuck: what the site asked for in plain words (a "prove you're a person" check, a code, a warning, a document FreeApply doesn't have, a question only you can answer), with "I applied myself", "Try again later" and "Skip this job".

Configuration

What

Where

Data folder

~/.freeapply, or the FREEAPPLY_DATA environment variable

Use an existing database in place

~/.freeapply/config.json: {"db": "C:/path/jobs.db"}, or FREEAPPLY_DB

Dashboard port

FREEAPPLY_PORT (default 7878; the next free port is used if it is taken)

Dashboard only

node agent/src/main.js --dashboard

Flags

--data <dir>, --db <file>, --port <n>, --skills-dir <dir> (repeatable; skill files are kept equal to the signed workflow)

Tools

18 tools, each with a title, annotations (read-only, destructive, idempotent) and a description of every parameter: freeapply_status (can FreeApply run, plus the signed procedure for a task), freeapply_open_dashboard, freeapply_get_settings (all settings or just the sections a step needs), freeapply_update_settings (settings, the résumé text and profile, and the AI models scan that picks a model for each part of the work), freeapply_fetch_posting (fetches and trims postings on your computer to save tokens, with their ATS keywords), freeapply_claim_job (claim or skip a job, with the duplicate, job-site and pay-floor checks), freeapply_check_text (truthfulness check; saves a passing cover letter as a PDF), freeapply_user_answers (get a job's answers or save a reusable one), freeapply_find_site_account, freeapply_clear_to_submit (clearance before each submit, and the unattended run's budgets), freeapply_update_job (your side: found to applied), freeapply_report_site_problem, freeapply_autorun (start or finish unattended runs), freeapply_list_jobs, freeapply_job_stats, freeapply_reply_check (frames an email reply check; with an app password saved in Settings it reads, stars and labels the replies itself), freeapply_record_outcome (what an employer did, from an email or the user), freeapply_shared_data (preview or send shared data). Removing a job is a dashboard action only (Applications → Remove); the agent has no tool for it. Every call is checked against the tool's parameters first: a missing, unknown or wrongly typed parameter returns one error naming each problem, and nothing changes.

Skills for Claude Code: freeapply-setup, freeapply-apply, freeapply-replies. Each points to its signed procedure.

Check a download

Every package comes with a .sig.json file holding its SHA-256, signed with an Ed25519 key whose private half never leaves our offline machine. The public keys are in agent/keys/. Compare the checksum with the one in latest.json:

Get-FileHash .\freeapply.mcpb -Algorithm SHA256      # Windows
shasum -a 256 freeapply.mcpb                         # macOS, Linux

The installer and the app's own update check do this and the signature check for you; a download that doesn't match is refused.

This repository

Path

What

agent/

The app: an MCP server in Node.js with no dependencies, the dashboard (web/), the legal texts (web/legal/), the signed workflow and the public keys. It is also the Claude Desktop extension (manifest.json).

skills/

Claude Code skills that point to the signed procedures

.claude-plugin/, .mcp.json

Claude Code plugin and marketplace files

release-notes/

What changed in each version

LICENSE

MIT License for the source code

License

The source code is released under the MIT License. The FreeApply name and logo are not covered by it; use of FreeApply and of the services we host is governed by the Terms of Service.

Contact

MyBotsAI · mybotsai@gmail.com.

Available Tools

18 tools
freeapply_check_repliesRun a reply check: plan, read, mark, finishA
Idempotent

Runs one email reply check (the freeapply-replies procedure), always beginning with action start, and, when the user saved an email login in Settings, reads and marks their mailbox itself. Each email found is recorded with freeapply_record_outcome. Use: start first; then read (start's mail.reader freeapply) or the Gmail connector (connector); mark after recording each email read returned; finish once everything found is recorded. Behavior: start: read-only, repeatable. read: signs in with the app password kept on this computer (you never see it), returns matching emails, changes nothing. mark: stars and/or labels one email as the user chose in Settings. finish: sets the last check to now, so the next check reads only newer email: only after recording everything found. Returns: start (the plan) {since, gmail (the user's mail settings: action none|star|label|star_and_label, label_name, ...), mail {reader: freeapply|connector, address}, applied [{job_id, company, title, submitted_at}], known_message_ids (already recorded)}. read {emails: [{gmail_message_id, gmail_thread_id, sender, subject, received_at, text}] newest first, already-recorded left out, count}. mark {mail_action} (for freeapply_record_outcome). finish {last_check}. Errors: an action other than start, read, mark or finish; read or mark without a saved email login; the mail server refusing the login.

NameRequiredDescriptionDefault
kindNoRequired for mark: the outcome you recorded for the email.
actionYesstart (always first): the plan; read: the mailbox; mark: star or label one email; finish (always last): the check is done.
gmail_message_idNoRequired for mark: the email's id, from read.

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well past the annotations by disclosing per-action behavior: start is read-only and repeatable, read authenticates with a locally stored app password the agent never sees and changes nothing, mark mutates stars/labels per the user's Settings choice, and finish advances the last-check watermark, which changes future read results. It also lists failure modes (unknown action, missing saved login, server login refusal). With destructiveHint=false but real state mutation, this is exactly the context an agent needs.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with a one-line purpose, then cleanly sectioned into Use/Behavior/Returns/Errors, so an agent can scan to the part it needs. It is dense and parenthetical-heavy, and the Returns block is long, though that length is largely licensed by the absence of an output schema.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a four-mode state machine with no output schema, the definition covers sequencing, authentication requirements, mutation semantics, and the full return shape of each action (plan, email list with field names and ordering, mail_action, last_check). Errors are enumerated, so nothing material is missing before a call.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is already 100%, so baseline is 3; the description adds value by tying parameters to the state machine (mark depends on an email id returned by read, and the mark supplants the freeapply_record_outcome kind), which the schema alone does not connect. It stops short of restating per-parameter requirements, so it is incremental rather than exhaustive.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a concrete verb and resource ("Runs one email reply check") and explicitly names the coupled sibling freeapply_record_outcome for recording each found email, so the boundary is clear without opening any schema. It also names the two mailbox paths (freeapply reader vs Gmail connector), which distinguishes it from the account/settings tools in the sibling list.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The "Use:" line gives an explicit ordered protocol — start first, then read via freeapply reader or the Gmail connector, mark after each read email is recorded, finish once everything found is recorded. Exclusions are stated too (finish "only after recording everything found"), leaving nothing to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

freeapply_check_textCheck text and save the cover letterA
Idempotent

Checks a cover letter or free-text answer against what the user really has; saves a passing cover letter as a PDF to upload. Every piece of prose is checked here before you type or attach it (freeapply_update_job only records). Use: before typing any written answer or attaching any letter, and after each fix. Not for short fields straight from settings (name, date, yes/no). Behavior: flags every skill, tool, number or claim the résumé, settings, highlights and saved answers don't support. Without save, changes nothing. With save, a passing letter becomes a PDF in the documents folder, kept with the job; a failing one is never saved; saving again replaces the file; refused once the job is applied. Until setup has stored the résumé's text, most claims are reported unsupported. Returns: {ok, problems} (plain sentences: fix, remove or ask the user). With job_id also keywords {used, unused}: the posting's supported skills this text uses / could still use. With save also file {path, name, bytes}, or note (why not saved). Errors: save without kind cover_letter and job_id; unknown job_id.

NameRequiredDescriptionDefault
kindNocover_letter: also checks the user's length, sign-off, leftover placeholders and that the company is named. answer (default): facts only.
saveNoSave a passing cover letter as a PDF (default false). For a letter, pass it from the first call: checked and saved at once.
textYesThe letter or answer, exactly as you will type or attach it.
job_idNoAdds the posting's keywords; numbers from the job's posting, title, pay, location and posting id, and the user's answers for this job, count as facts. Needed for save.
companyNoThe employer, when there is no job_id.

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well beyond annotations: explains that without save nothing changes, a passing letter becomes a PDF kept with the job, a failing letter is never saved, saving again replaces the file, saving is refused once the job is applied, and claims are mostly unsupported until setup has stored the résumé text. It also names the specific checks (skills, tools, numbers, claims) and the error conditions.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Well structured with labeled Use, Behavior, Returns and Errors sections. Despite being long, every section front-loads the decision-relevant information and no sentence is wasted.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description fully compensates by documenting the return shape ({ok, problems}, keywords, file, note) and the error cases. Combined with the detailed usage and behavior sections, an agent has everything needed to call this correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3. The description still adds useful cross-parameter constraints: save requires kind cover_letter and job_id, company is the fallback when job_id is absent, and job_id activates keyword analysis and treats posting facts as supported.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource: checks a cover letter or free-text answer against the user's real facts and optionally saves a passing cover letter as a PDF. It explicitly distinguishes itself from freeapply_update_job ('only records') and from short settings-derived fields, so an agent can route correctly without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides explicit timing ('before typing any written answer or attaching any letter, and after each fix') and explicit exclusions ('Not for short fields straight from settings (name, date, yes/no)'), plus names the sibling that only records. No inference required.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

freeapply_claim_jobClaim or skip a jobA

Claims a job before you work on it: duplicate check, the user's rules, starts tracking, returns the job_id every later call needs. Makes the job's first record (listing: freeapply_list_jobs; changing: freeapply_update_job). Use: before opening any application form; also to record a reviewed job you won't pursue (status skipped + status_note) so it isn't reviewed again. Not for a job already claimed. Behavior, first match wins: posting id already tracked: returns that job (existing true, nothing added); job site the user didn't choose, or signed out or paused: refused (refused says why, sites lists ready ones); same company and title as an applied job: refused as a repost; posted pay below the user's minimum: saved as skipped (rule pay_floor). Otherwise the job is added. A refused or existing claim changes nothing, so repeating the call is safe. Returns: {job_id, existing, status, rule, earlier}. earlier: up to 20 other jobs at the company [{id, title, company, status, same_title}]; if an applied one is clearly the same role under another title, mark this one skipped (freeapply_update_job). restart true (auto-run): the user saved new settings and wants them used now: don't work this job; the run finishes and starts again. Errors: a missing title or company.

NameRequiredDescriptionDefault
urlNoPosting URL; tells the job site. The URL just read by freeapply_fetch_posting keeps its keywords.
titleYesAs posted.
sourceNoWhere found: job site id (linkedin, indeed, company_sites, ...) or referral; tells the job site like url.
statusNofound (default): to work on; skipped: a job you won't pursue.
companyYesThe employer as posted; not a staffing firm, when you can tell.
pay_maxNoHighest posted pay, a number. Feeds the pay floor.
pay_minNoLowest posted pay, a number: annual, or hourly if posted hourly. Feeds the pay floor.
locationNoAs posted.
pay_textNoPay exactly as posted, e.g. "$90k-$110k".
apply_urlNoApplication form URL, if different.
fit_notesNoWhy it fits or doesn't, one sentence.
fit_scoreNo0-100, scored as the apply procedure says.
work_modeNoremote, hybrid or onsite, as posted.
descriptionNoShort description or key requirements.
external_idNoThe posting's id on its source site; pass it whenever shown: finds the posting again and catches reposts.
status_noteNoFor skipped: why, one plain sentence.

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only cover the generic mutation/safety profile, but the description supplies the full decision cascade (already tracked, disallowed/signed-out/paused site, repost match, pay-floor skip), the return shape {job_id, existing, status, rule, earlier} with the meaning of 'earlier' and 'restart', and the missing title/company error. It also discloses the idempotence-like safe-repeat property, which is a mild tension with idempotentHint=false but reads as clarifying the actual state behavior rather than contradicting it.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with purpose and usage, then a clearly labeled 'Behavior, first match wins' block that prioritizes rules over prose. The telegraphic colon-chained style packs value but is dense enough that an agent must parse carefully to find the branch it needs.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 16-parameter mutation tool with no output schema, the description covers the refusal conditions, the effective return contract including the 'earlier' list and 'restart' flag, and error behavior. Nothing an agent needs in order to call it correctly and interpret the result appears to be missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, but the description adds real meaning: it explains how status=skipped plus status_note are used together for reviewed-but-unpursued jobs, and how posted pay feeds the pay_floor rule outcome. It stops short of walking through the remaining optional posting fields, which the schema already documents well.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource up front ('Claims a job before you work on it') plus the immediate side effects (duplicate check, rules, tracking) and the returned job_id. It also names what it is not by pointing to freeapply_list_jobs for listing and freeapply_update_job for changing, so it is distinguishable from every sibling without opening a schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives explicit when-to-use ('before opening any application form'), a secondary use case (recording a reviewed job not pursued via status skipped + status_note), and an explicit exclusion ('Not for a job already claimed'). Alternative tools are named for the adjacent operations, leaving nothing to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

freeapply_clear_to_submitGet clearance to submitA

Go-ahead for one submit after checking the pace, the user's limits and, in auto-run, the Stop button. Comes right before the submit; freeapply_update_job refuses applied without its clearance. Use: right before every submit, with job_id. Not early, not for a job you won't submit now: each clearance counts toward the per-minute pace at once. Behavior: at most 3 submits a minute (or the user's slower setting) and the user's daily cap. A clearance: one job, 15 minutes, used up when applied is recorded; asking again for the same job issues a new one; kept only while FreeApply runs. Parameters: job_id ties the clearance to that one job (without it you only see the pace). method: external (employer or ATS form, the default), easy_apply or email; the pace and daily cap count submits by that method, and easy_apply also needs one-click apply allowed in Settings. run_id, only in auto-run (from freeapply_manage_autorun start), adds the user's Stop and limits, and counts as the run checking in. Returns: {clear, advice, last_minute, limit_per_minute, today, daily_cap}, plus clearance {job_id, expires_at} when clear. clear false: don't submit; prepare the next job, call again later. refused: one-click apply is off; apply on the employer's site or skip the job. stop_run true (with reason): the run must end now: freeapply_manage_autorun action finish. restart true: the user saved new settings and wants them used now: submit and record this job, start no other, finish the run; the next begins at once.

NameRequiredDescriptionDefault
job_idNoThe job about to be submitted.
methodNoHow you will submit (default external).
run_idNoAuto-run only: the run_id from freeapply_manage_autorun start.

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With annotations already declaring non-read-only, non-idempotent, and non-destructive behavior, the description adds substantial stateful context: rate limits, daily caps, 15-minute clearance expiry, one-job scope, method-specific counting, and auto-run Stop/restart semantics. These details go well beyond what the annotations provide.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is dense and well-structured with Use, Behavior, Parameters, and Returns sections, and the core purpose is front-loaded. It is somewhat long and repeats the 'right before submit' timing in the opening and Use section, but the length is largely justified by the tool's stateful complexity.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a complex, non-idempotent stateful tool with no output schema, the description is complete enough: it explains preconditions, rate limits, parameter effects, return fields, and how to react to clear=false, refused, stop_run, and restart outcomes.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, but the description still adds meaningful semantics: job_id ties clearance to one job and without it only pace is visible; method affects pace/daily cap and easy_apply requires one-click apply enabled; run_id only applies in auto-run and activates Stop/limits and run check-in behavior.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific action and resource: a go-ahead/clearance for one submit, checked against pace, user limits, and auto-run Stop state. It also distinguishes itself from freeapply_update_job by noting that job update refuses 'applied' without this clearance.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives explicit timing and exclusions: use right before every submit, with job_id, not early, and not for a job that will not be submitted now. It also routes stop_run handling to freeapply_manage_autorun action finish.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

freeapply_fetch_postingFetch a job postingA
Read-onlyIdempotent

Fetches one job posting from the user's computer, trimmed: description, form questions, suggested answers, skills asked. Costs few tokens next to the browser, which you still use to fill and submit the form. Use: read each posting you found before scoring or applying. FreeApply has no job search of its own: search the user's job sites in the browser. Not for search-result or sign-in pages: read those in the browser. Behavior: read-only; one web request. Greenhouse, Lever, Ashby via their public APIs, other sites as page text. Public http(s) only: an address on this computer or a local network, or a redirect to one, is refused. Remembered this session, so freeapply_claim_job keeps its keywords. Parameters: url, the posting or its application form; max_chars caps only the description (default 6000, at least 500; description_chars tells you when it was cut); source, the job site where you found it (e.g. linkedin), picks the saved answers meant for that site. Returns: ats, title, company, location, work_mode, pay, description, description_chars (full length), questions [{label, required, type, options}], suggested_answers (from settings and saved answers; answer anything else only from the résumé or the user), keywords {matched, missing, coverage}: use matched in the posting's words, never claim missing; coverage = matched share in %, null if the posting names none. Errors: a bad or local address, or an unfetchable page, with the reason: read it in the browser. Next: freeapply_claim_job.

NameRequiredDescriptionDefault
urlYesThe job page or its application form.
sourceNoJob site id where found, e.g. linkedin.
max_charsNoDescription cap in characters (default 6000).

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only cover read-only/idempotent/open-world, but the description adds substantive behavior: one web request, which sites use public APIs vs. page text, refusal of localhost/private-network addresses and redirects to them, and session-level caching so freeapply_claim_job retains keywords. It also specifies error behavior and recovery ("read it in the browser").

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Labeled sections (Use / Behavior / Parameters / Returns / Errors / Next) make it scannable and the critical routing guidance is front-loaded. It is long, and the token-cost aside ("Costs few tokens next to the browser...") is the least essential sentence, though it does reinforce the browser-vs-tool split.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema and no annotations covering returns, the description fully carries that burden: it enumerates every returned field including items, suggested_answers provenance, and the keywords/coverage semantics with usage rules ("use matched in the posting's words, never claim missing"). Errors and the natural next tool are also documented.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% so the baseline is 3; the description goes beyond it by explaining that max_chars caps only the description and that description_chars signals truncation, and by explaining what `source` functionally does (selects saved answers for that site). The url semantics are merely restated ("the posting or its application form"), which is already in the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ("Fetches one job posting") plus exactly what is returned (description, form questions, suggested answers, skills asked). It also disambiguates from siblings by naming freeapply_claim_job as the next step and clarifying that search happens in the browser, not here.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicit when-to-use ("read each posting you found before scoring or applying") and explicit when-not ("Not for search-result or sign-in pages: read those in the browser"), plus the key constraint that FreeApply has no job search of its own. It routes to the correct alternative for the excluded cases.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

freeapply_find_site_accountFind the user's employer-site accountA
Read-onlyIdempotent

Whether the user already made an account on an employer's careers site, and with which email. Employer sites only (job boards such as LinkedIn that signed the user out: freeapply_report_site_problem). Use: when an application form asks you to sign in or create an account. Not for signing in or up: FreeApply stores no passwords and you never type one. Behavior: read-only. The user records the accounts they make on the dashboard's Needs you tab. Parameters: site, the host the sign-in form is on, or any URL there. It is reduced to the domain without www. and matched exactly, so careers.example.com and example.com are different sites: pass the one the form is on. Returns: known account {domain, email_used, created_at, job_id, note}: ask the user to sign in in the browser, then continue in their session. None {domain, account: null}: freeapply_update_job status needs_account, account_url = the sign-up page. Errors: a site that isn't a domain or web address.

NameRequiredDescriptionDefault
siteYesDomain or any URL on it, e.g. careers.example.com.

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly/idempotent, so the bar is lower, but the description still adds substantial context beyond them: the data source (accounts the user records on the dashboard's Needs you tab), the authentication boundary (no passwords stored), and the two branch outcomes with concrete field names.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Labeled sections (Use / Behavior / Parameters / Returns / Errors) make it scannable and the purpose is front-loaded. It is dense and slightly long, but nearly every clause carries actionable information; only the returns-section next-step guidance could be trimmed.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description supplies the return shapes for both branches (account object fields vs. {domain, account: null}), the follow-up action for each, and the error condition. Nothing an agent needs to invoke or interpret this tool is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% (baseline 3), but the description adds genuinely new meaning: the input is normalized to the domain with 'www.' stripped and matched exactly, so careers.example.com and example.com are distinct — and it tells the agent which one to pass. That is exactly the failure mode an agent would otherwise hit.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

First sentence states a specific question the tool answers: whether the user already has an employer careers-site account and with which email. It scopes the resource explicitly ('Employer sites only') and names the excluded class (job boards like LinkedIn) plus the sibling that handles them.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives an explicit trigger ('when an application form asks you to sign in or create an account') and an explicit exclusion ('Not for signing in or up: FreeApply stores no passwords and you never type one'). It also names freeapply_report_site_problem for job boards and freeapply_update_job for the not-found branch, so alternatives are fully routed.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

freeapply_get_settingsRead the user's settingsA
Read-onlyIdempotent

Reads the user's settings: who they are, what they seek and how FreeApply should work. Single form answers: freeapply_manage_answers; whether FreeApply can run: freeapply_get_status. Use: once per session or helper, and again after each auto-run go, before scoring jobs or filling a form. With the résumé text and the user's own words, the only source of facts about the user: never invent beyond it. To change: freeapply_update_settings. Behavior: read-only; never includes installation secrets. Parameters: sections, the sections to return (default all, named under Returns): ask only for what the step needs, e.g. ["profile", "eligibility"] for a form, and leave out resume, the largest, unless you need its text. Returns: {settings, missing}. Sections: profile, targets, eligibility, resume (file paths, text, profile; the user adds and replaces résumé files in the dashboard), cover_letter, automation, autorun, gmail, custom_answers, models, model_choices, sharing (choices only). missing: required fields still empty [{key, label}]; while non-empty, apply nowhere: open the settings tab (freeapply_open_dashboard) and ask the user to fill them. Errors: an unknown section; the message lists valid ones.

NameRequiredDescriptionDefault
sectionsNoSection names to return (default all).

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the annotations' read-only/idempotent hints, it discloses security context ('never includes installation secrets'), an epistemic constraint ('the only source of facts about the user: never invent beyond it'), and critical gating behavior: while `missing` is non-empty, 'apply nowhere' and the agent should open the settings tab. It also describes error behavior for unknown sections.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded and broken into labeled segments (Use, Behavior, Parameters, Returns, Errors), with no wasted sections. It is dense but mostly earns its length; the sentence 'With the résumé text and the user's own words, the only source of facts about the user: never invent beyond it' is slightly awkward and could be clearer.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a one-parameter read tool with rich annotations but no output schema, the description covers everything an agent needs: return shape ({settings, missing}), the full section list, missing-field gating, and error handling. Nothing material is missing to call or interpret it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema already documents the `sections` parameter at 100% coverage, so the baseline is 3. The description significantly adds meaning by enumerating valid section names under Returns, advising to request only what the step needs with a concrete example, and warning that `resume` is the largest and should be omitted unless its text is required.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: 'Reads the user's settings: who they are, what they seek and how FreeApply should work.' It explicitly distinguishes itself from freeapply_manage_answers, freeapply_get_status, and freeapply_update_settings, so an agent can route correctly without opening schemas.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives explicit timing: 'once per session or helper, and again after each auto-run go, before scoring jobs or filling a form.' It also names the alternatives for single-form answers and status checks, and directs changes to freeapply_update_settings. When and when-not are both covered.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

freeapply_get_statsGet job-search statisticsA
Read-onlyIdempotent

The user's job search in numbers: applications, replies, interviews, offers, rates (individual jobs: freeapply_list_jobs; whether FreeApply can run: freeapply_get_status). Use: to report progress, e.g. when wrapping up a session. Not for finding a particular job. Behavior: read-only, cheap: counted fresh from the local database each call, nothing cached. No parameters. Returns: tracked, applied, applied_today, queued, needs_you (jobs waiting on the user), interviews, offers, rejections, acknowledged, response_rate (% of applications with a real reply; automatic acknowledgements not counted), avg_fit, last_reply_check (when the last Gmail reply check finished), counts by_status, by_outcome, by_method, daily (applications per day), top_companies, top_titles, top_jobs.

NameRequiredDescriptionDefault

No parameters

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly/idempotent/non-destructive, yet the description still adds value beyond them: 'counted fresh from the local database each call, nothing cached' discloses cost and data freshness, which annotations cannot express. It also defines a non-obvious metric inline ('response_rate – % of applications with a real reply; automatic acknowledgements not counted') and clarifies last_reply_check.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with a one-line purpose, then labeled Use/Behavior/Returns blocks. The Returns enumeration is long but each field grouping (counts, rates, aggregations) earns its place because no output schema exists. Slightly dense, but structured rather than rambling.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description must convey what comes back, and it does so field-by-field including units (percent) and semantics (needs_you = jobs waiting on the user; daily = applications per day). Combined with cost/freshness disclosure, an agent has everything needed to call and interpret it.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Zero parameters, so the schema carries nothing to explain; the description correctly states 'No parameters', removing any question about required filters. It stops there rather than adding semantics a parameterless tool would need, which is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Opens with a concrete verb+resource framing ('The user's job search in numbers: applications, replies, interviews, offers, rates') and immediately names the two siblings it is not (freeapply_list_jobs, freeapply_get_status). An agent can distinguish this from list_jobs and get_status without opening any schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicit usage section: 'Use: to report progress, e.g. when wrapping up a session. Not for finding a particular job.' Both a positive trigger and an exclusion are stated, and the alternative for per-job lookups is named. Nothing is left to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

freeapply_get_statusCheck FreeApply and get a procedureA
Read-onlyIdempotent

Whether FreeApply can work now, plus the signed step-by-step procedure for a task. About FreeApply itself (user details: freeapply_get_settings; job search: freeapply_get_stats). Use: first in every session and before each task; with wait after asking the user to accept the Terms or finish setup in the dashboard. Works while locked or the Terms are unaccepted, so it can say why. Behavior: read-only: reports what FreeApply set up when it started (data folder, database, dashboard, the résumé copy to upload). wait holds the call up to 10 minutes until the Terms are accepted and setup is complete, and returns within seconds of that. Parameters: none for status only; procedure adds that task's signed steps; lane (with procedure freeapply-apply) is for a helper: only the hard rules and that lane's steps, with a short status; wait as above, with or without procedure. Returns: workflow {ok, problem}, terms {ok}, setup_complete, missing, sites [{id, name, ready}] (chosen job sites), autorun, update, dashboard (URL), data_dir, documents {dir, resume, cover_letters}, stats, procedures, models {can_delegate, rescan, levels, lanes, unfilled} (each level and lane {model, effort, source}; model current = your own model does it). With procedure also procedure {name, description, text, workflow_version, workflow_hash}, null while locked. wait_again true: a wait ran out first; call again. Next: workflow.ok false: tell the user why, stop. terms.ok or setup_complete false: follow freeapply-setup. models.rescan true: do its AI models step first.

NameRequiredDescriptionDefault
laneNoA helper's lane of freeapply-apply; the agent that starts helpers omits it.
waitNoHold the call until the Terms are accepted and setup is complete (up to 10 minutes).
procedureNofreeapply-setup (first run; Terms or settings missing; starting auto-run), freeapply-apply (find jobs, apply) or freeapply-replies (email reply check).

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly/idempotent/destructive=false, but the description adds substantial non-obvious behavior: wait can hold up to 10 minutes until Terms are accepted, returns within seconds of completion, and it discloses what setup state is reported. It also explains wait_again semantics for a timed-out wait.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Structure is excellent — purpose, use, behavior, parameters, returns, and next steps are clearly separated and front-loaded. It is dense and the Returns enumeration is long, but almost every clause carries actionable information for a complex tool; minor verbosity only.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

No output schema exists, so the description must explain returns — and it does thoroughly, enumerating the workflow, terms, setup, sites, documents, and procedure fields. It also provides failure-branch guidance (workflow.ok false → stop; terms/setup false → freeapply-setup; rescan → models step), making it complete for a tool of this complexity.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, but the description materially adds meaning: 'lane (with procedure freeapply-apply) is for a helper: only the hard rules and that lane's steps,' which explains an interaction constraint the schema does not. It doesn't fully enumerate each param's individual effect, but the added interaction semantics push it above baseline.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening line states a specific dual purpose: reporting whether FreeApply can work now and returning a signed step-by-step procedure. It also explicitly disambiguates from siblings by naming freeapply_get_settings (user details) and freeapply_get_stats (job search), so an agent can route without opening schemas.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is prescriptive: 'first in every session and before each task,' and use the wait flag after asking the user to accept Terms or finish setup. It even notes it works while locked/unaccepted, so its purpose as a diagnostic tool is unambiguous.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

freeapply_list_jobsList tracked jobsA
Read-onlyIdempotent

Lists the user's tracked jobs, most recent activity first (submitted, else updated, else found): the jobs themselves (totals and rates: freeapply_get_stats). Use: to find a job_id, look up one job by job_id, or answer questions about particular jobs. Not for adding or changing jobs (freeapply_claim_job, freeapply_update_job). Removing a job is the user's, in the dashboard. Behavior: read-only. Filters combine: a job must match all given. limit and offset page through the same order (default 200 from 0); a page shorter than limit is the last. Parameters: job_id returns just that job (empty if unknown); status and outcome match exactly; search finds text in the title, company or location, ignoring case. Returns: [{id, title, company, location, work_mode, pay_text, pay_min, pay_max, url, apply_url, fit_score, status, status_note, outcome, outcome_at, source, found_at, updated_at, method, submitted_at, confirmation, resume_path, cover_path, reply_count}]; empty when nothing matched.

NameRequiredDescriptionDefault
limitNoMost jobs to return (default 200).
job_idNoOne job by its id.
offsetNoJobs to skip (default 0).
searchNoText to find.
statusNoExact status filter.
outcomeNoExact employer-outcome filter.

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint/idempotentHint/destructiveHint, so the 'read-only' line is redundant, but the description goes well beyond them: filter combination is AND across all given params, pagination preserves the same ordering with a short-page-means-last rule, and empty results are specified for both no-match and unknown job_id. That is the kind of behavioral detail annotations cannot express.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with purpose, then clearly segmented into Use / Behavior / Parameters / Returns, with zero filler. The enumerated 21-field return list is long, but it substitutes for a missing output schema, so it earns its space; only the restated defaults are pure repetition.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the field-level return list is exactly what an agent needs to know what it will get back, and ordering, filtering, pagination limits, and empty-result behavior are all covered. Nothing an agent needs to invoke this correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline would be 3; the description earns above that by adding semantics the schema lacks — 'search' is scoped to title, company or location and is case-insensitive, job_id returns empty (not an error) when unknown, and status/outcome are exact matches. The default-200/offset-0 behavior is restated rather than added, keeping it off a 5.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Lists the user's tracked jobs') plus the exact ordering rule (submitted, else updated, else found). It explicitly separates itself from freeapply_get_stats (totals/rates) and freeapply_claim_job / freeapply_update_job (mutation), so an agent can route correctly without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

A dedicated 'Use:' clause enumerates the three concrete jobs this serves (find a job_id, look up one job, answer questions about particular jobs), and a 'Not for' clause names the sibling tools that handle adding/changing plus notes that removal happens in the dashboard. Both the positive and negative routing conditions are explicit.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

freeapply_manage_answersGet or save the user's answersA
DestructiveIdempotent

Gets or saves the user's own answers to specific form questions, so you never guess one (general details: freeapply_get_settings). A new question for the user goes through freeapply_update_job status needs_info instead. Use: get before retrying a job the user re-queued from the Needs you tab; save when the user answers a question in this conversation, for later forms. Save only the user's own words: saved answers count as facts in freeapply_check_text. Behavior: get is read-only. save replaces the answer saved under the same question; an empty answer removes it. Returns: get {job_id, answers: [{label, answer}] the user gave for this job, saved_answers: {question: reusable answer}, cover_letter: the job's saved letter {path, text} (text: for a text-box letter field) or null}. save {label, saved, removed, saved_answers}. Errors: get without job_id or with an unknown one; save without label; an action other than get or save.

NameRequiredDescriptionDefault
labelNoRequired for save: the question as forms word it, e.g. "Are you willing to relocate?".
actionYesget (read-only): a job's answers and saved letter; save (writes): one reusable answer the user just gave.
answerNoFor save: the user's own words; empty removes the saved answer.
job_idNoRequired for get.

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well beyond the annotations: it discloses that save replaces the answer under the same question and that an empty answer removes it, which explains the destructiveHint=true and idempotentHint=true flags in concrete terms. It also warns that saved answers count as facts in freeapply_check_text, a downstream effect an agent could not infer, and lists error conditions.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads the core verb+resource, then organizes the rest into labeled Use/Behavior/Returns/Errors segments, which is easy to scan. Slightly dense with parenthetical cross-references, but every sentence carries actionable information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description compensates by spelling out both return shapes (job_id, answers, saved_answers, cover_letter for get; label, saved, removed, saved_answers for save) and the error cases. Nothing an agent needs to call this correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so label, action, answer, and job_id are already fully documented with the same wording ('the user's own words', 'empty removes the saved answer'). The description adds error conditions tied to parameters (get without job_id, save without label) but little semantic detail beyond the schema, so baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb pair and resource: gets or saves the user's own answers to specific form questions. It immediately distinguishes itself from freeapply_get_settings (referenced as 'general details') and from freeapply_update_job with status needs_info for brand-new questions.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The 'Use:' sentence gives explicit triggering conditions for each action — get before retrying a re-queued job, save when the user answers in-conversation. It also names the alternative path for a new question (freeapply_update_job status needs_info), so when-not-to-use is covered.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

freeapply_manage_autorunStart or finish an auto-runA

Keeps FreeApply applying on its own from this session, with no scheduled task: start waits until something is due, finish ends a run (freeapply_get_status only shows the run state). Use: auto-run mode of freeapply-apply, which setup's last step enters: start with wait (takeover on the first call), finish after each run, then start again. Not in a session the user runs by hand. Behavior: start with wait holds the call up to 10 minutes while nothing is due (auto-run stopped by the user's Stop or a limit in Settings, the rest after a search found nothing new, the daily cap) and returns as soon as something is, within seconds of the user pressing Start. One session runs it at a time. A run checks in with each job-work tool call and freeapply_clear_to_submit (15 minutes without one counts as ended); freeapply_clear_to_submit with the run_id ends it at a hard stop. finish releases the run and starts the rest (autorun.every_hours), or none when the user asked for a restart with new settings; harmless on a run that already ended. Parameters: action start or finish. wait (start): hold as above; without it start answers at once. takeover (start with wait): only on the call right after the user asked for setup or to keep applying: it presses Start (clears a Stop, a reached limit and the rest) and makes this session the runner; the session it replaced gets replaced at its next start. run_id (finish): the run start returned. summary (finish): one line shown in the dashboard's run history. Returns: start {go: true, run_id, minutes (left before the time limit, null: none), max_applications, sites}; {go: false, replies_due: true}: do freeapply-replies, then start again; {go: false, needs_user: terms|setup}: ask the user (freeapply_open_dashboard), freeapply_get_status with wait, then start again; {go: false, wait_again: true}: start again; {go: false, replaced: true} or any other go false: end quietly. finish {finished, applied_this_run}, null for a run no longer active. Errors: finish without run_id; an action other than start or finish.

NameRequiredDescriptionDefault
waitNoFor start in auto-run mode: hold until something is due.
actionYesstart a run (with wait: when one is due); finish it.
run_idNoRequired for finish.
summaryNoFor finish: e.g. "applied 4, needs you 2" (up to 500 characters).
takeoverNoFor start with wait: the call right after the user asked to start.

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well beyond annotations by describing the 10-minute wait behavior, takeover semantics, single-runner constraint, check-in requirements, hard-stop behavior via freeapply_clear_to_submit, and finish scheduling. These are critical stateful behaviors for an agent orchestrating the auto-run loop.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long and dense, but it is structured into purpose, usage, behavior, parameters, returns, and errors. Most sentences carry necessary state-machine semantics, though some parentheticals could be tightened without losing meaning.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Covers the full control flow for a complex stateful tool: expected returns for go true/false branches, needs_user handling, replaced/wait_again cases, finish return values, and error conditions. With no output schema, this description provides the return semantics an agent needs.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Although schema coverage is 100%, the description adds operational meaning: wait holds until something is due, without wait start answers immediately, takeover applies only to the call right after the user asked, run_id is from start, and summary appears in dashboard history. This materially supplements the terse schema descriptions.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific workflow verb/resource: keeping FreeApply applying automatically via start/finish actions. It explicitly distinguishes itself from freeapply_get_status and from manual user-run sessions, so an agent can identify its role without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides explicit usage sequencing: start with wait, finish after each run, then start again, as part of setup's auto-run mode. It also says when not to use it (a session the user runs by hand) and names freeapply_get_status as the state-only alternative.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

freeapply_open_dashboardOpen the dashboard in the browserA
Read-onlyIdempotent

Opens the local FreeApply dashboard in the user's browser, one tab (freeapply_get_status only reports its URL). Use: when the user must act there: accept the Terms, fill settings, answer questions waiting on them, review applications and replies. Not for reading data: other tools return it. Behavior: changes no data. Starts the dashboard if needed at http://127.0.0.1:7878 or the next free port; reachable only from this computer. Parameters: tab, the page to open: overview (default; shows the Terms until they're accepted), settings (setup fields), issues (Needs you: questions, sign-ups), applications or replies. Returns: {url, opened}. url null: it couldn't start (no free port); tell the user. opened false with a url: no browser launched; give the user the url.

NameRequiredDescriptionDefault
tabNoThe page to open (default overview).

TDQS

A5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly/idempotent/non-destructive/non-open-world, but the description adds real context beyond them: no data is changed, the dashboard is started on demand with a port fallback (127.0.0.1:7878 or next free port), and it is reachable only from this machine. It also discloses the two failure modes and what the agent should do in each.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the action, then organized under Use:/Behavior:/Parameters:/Returns: labels so an agent can scan to the section it needs. Dense rather than padded — no sentence repeats a structured field verbatim, and the Returns guidance is load-bearing because there is no output schema.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Though no output schema exists, the description documents the return shape ({url, opened}) and the meaning of each degenerate case, plus the localhost-only constraint and side effects. Nothing needed to invoke it correctly or interpret the result is missing for a single optional-enum-parameter tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is already 100% with an enum, so the baseline is 3, but the description goes further by explaining what each enum value actually surfaces — overview (default; shows the Terms until accepted), settings, issues ("Needs you"), applications, replies. That is meaning the schema does not carry, and it matters for choosing a tab.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ("opens the local FreeApply dashboard in the user's browser") and immediately delimits it against the nearest sibling: freeapply_get_status only reports the URL while this one actually opens a tab. An agent can pick between the two without opening either schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicit when-to-use list ("when the user must act there: accept the Terms, fill settings, answer questions waiting on them, review applications and replies") paired with an explicit exclusion ("Not for reading data: other tools return it"). Both the selection condition and the anti-pattern are named.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

freeapply_record_outcomeRecord what an employer didA
Idempotent

Records what an employer did with an application (your side, e.g. applied or skipped: freeapply_update_job). Use: for each employer email found in a reply check, between freeapply_check_replies start and finish, and when the user tells you about a call or corrects an outcome. Not for your own steps. Behavior: with an email (gmail_message_id): stores it; raises the job's outcome only if this email ranks higher than the current one (an interview outranks an acknowledgement); the same gmail_message_id again stores nothing new. Without an email: sets the outcome exactly, whatever its rank. The email fields fill the dashboard's Replies tab. Returns: with an email {recorded (false: recorded before), kind, job_id, outcome (the job's, afterwards)}, job_id and outcome null without job_id; without one {job_id, outcome}. Errors: an unknown job_id; no job_id and no email; an empty outcome with an email.

NameRequiredDescriptionDefault
job_idNoFrom the reply-check plan or freeapply_list_jobs. Required without an email; with one optional, but without it no outcome changes.
senderNoEmail: sender address.
companyNoEmail: the employer that sent it.
outcomeYesWhat the employer did: acknowledged (automatic 'we received your application' email), replied (a person replied), assessment (test, assignment or screening questionnaire), interview (interview requested or scheduled), rejected (rejection), offer (offer), withdrawn (candidate withdrew); or "" to clear it (without an email only).
subjectNoEmail: subject line.
summaryNoEmail: what it says, one sentence of at most 20 words, no personal data beyond what is needed.
mail_actionNoEmail: what you did with it in Gmail: starred, labeled:<name>, starred+labeled:<name> or none.
received_atNoEmail: when it arrived (ISO 8601).
gmail_thread_idNoEmail: Gmail thread id.
gmail_message_idNoThe employer email's Gmail message id.

TDQS

A5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the annotations, it explains the rank-based outcome update rule, duplicate-email idempotency, exact-setting behavior without an email, return shapes, and error cases. These details materially help the agent understand side effects and failure modes.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is dense but well structured with Use, Behavior, Returns, and Errors sections. It front-loads the core purpose and avoids wasting space on restating schema details.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given 10 parameters, no output schema, and non-trivial conditional behavior, the description covers usage, side effects, returns, and errors adequately. An agent has enough information to call it correctly in both email and non-email modes.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Although schema coverage is already 100%, the description adds crucial conditional semantics: with gmail_message_id the outcome is rank-gated, without it the outcome is set exactly, and job_id has different implications in each mode. It also explains what the email fields contribute to the dashboard.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: recording what an employer did with an application. It also explicitly distinguishes this from the user's own application steps, naming freeapply_update_job as the tool for that.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives explicit trigger conditions: for each employer email found during a reply check, and when the user reports a call or corrects an outcome. It also states what the tool is not for and routes that case to freeapply_update_job.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

freeapply_report_site_problemReport a job site signed out or limitedA
DestructiveIdempotent

Marks a job site the user chose in Settings (e.g. LinkedIn, Indeed) unusable for now: it signed the user out or showed its own daily limit (an employer's own careers site: freeapply_find_site_account). Use: as soon as a chosen site shows a sign-in page or a daily limit; then keep applying on the ready sites or company career sites. Never type a password. Behavior: signed_out: unavailable until the user signs in again and confirms it in the dashboard; limit_reached: paused until midnight. Meanwhile freeapply_claim_job refuses new jobs from it. Reporting again changes nothing; only the user can mark a site ready. Returns: {site, status, sites} (each chosen site with ready). Errors: a site the user didn't choose.

NameRequiredDescriptionDefault
siteYesJob site id, as freeapply_get_status lists it in sites.
statusYessigned_out: a sign-in page, or the site says you're signed out. limit_reached: the site's own daily limit, e.g. "You reached today's Easy Apply limit".

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well beyond the annotations: it explains the per-status consequences (unavailable until the user signs in and confirms; paused until midnight), the downstream effect on freeapply_claim_job, and that re-reporting is a no-op and only the user can restore readiness. That gives the agent the lifecycle and side effects of a destructiveHint=true mutation, which the annotations alone do not convey.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the action, then labeled Use/Behavior/Returns/Errors sections, with no filler sentences. The telegraphic, colon-heavy style is dense but each line carries information an agent needs.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Fills the gap left by the absent output schema by documenting the return shape {site, status, sites} and names the error case (a site the user didn't choose). Combined with the state-transition details, an agent has everything needed to call it correctly and interpret the result.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and both parameters are fully described in the schema, including enum meanings and example phrasing for limit_reached. The description adds only illustrative site examples and the note that only user-chosen sites are valid, so baseline 3 is right.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a precise verb+resource (marks a chosen job site unusable) with the concrete trigger conditions (signed out or daily limit). It also distinguishes the employer-careers case by routing to freeapply_find_site_account, so an agent can separate this from sibling tools without opening a schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives an explicit trigger ('as soon as a chosen site shows a sign-in page or a daily limit'), the required follow-up behavior ('keep applying on the ready sites or company career sites'), and a hard exclusion ('Never type a password'). Alternatives are named rather than implied.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

freeapply_share_dataPreview or send shared dataA
Idempotent

Shows or sends the exact data the user chose to share with the FreeApply server (the sharing choices themselves: freeapply_get_settings). Use: preview when the user asks what is shared; sync only when the user asks to send now (it also runs on its own every 12 hours). Not for changing the choices: the user does that in the dashboard (Settings, Data sharing). Behavior: preview: read-only, sends nothing, safe any time. sync: sends over the internet only what the current choices allow; can't be undone from here (the user can delete shared data in the dashboard); refused moments after the last sync. Returns: preview: the exact requests that would be sent: analytics_request (anonymous usage and job-market data), the talent-pool request only if the user joined; secrets hidden. sync: {sent, result} or {sent: false, reason}: Terms not accepted, a sync moments ago, or the server unreachable (the automatic sync retries later). Errors: an action other than preview or sync.

NameRequiredDescriptionDefault
actionYespreview (read-only, the usual choice): show what would be sent; sync (only when the user asks): send it now.

TDQS

A4.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description adds substantial context beyond the annotations: preview sends nothing, sync transmits only what current choices allow, cannot be undone from here, and is refused moments after a previous sync (a debounce the idempotentHint does not convey). It also enumerates sync failure reasons (terms not accepted, recent sync, server unreachable). It stops short of explaining auth/permission requirements, which keeps it at 4.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core sentence, then cleanly labeled Use/Behavior/Returns/Errors sections so an agent can skim. It is dense and long for a one-parameter tool, but nearly every sentence carries operational content rather than filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

There is no output schema, and the description compensates by describing the return payload for both modes, including windowing of secrets and the conditional talent-pool request. Error behavior and the side effect of sync over the network are also covered, leaving nothing essential missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 100% schema coverage on a single enum parameter the baseline is 3, but the description goes further by tying each value to a usage rule and a distinct return shape. The only gap is that it does not repeat the enum syntax, which the schema already handles.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description names the exact resource (the data the user chose to share) and distinguishes its two modes, preview and sync, in the very first sentence. It explicitly routes away from freeapply_get_settings for the choices themselves, so an agent can separate it from that sibling without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Use conditions are spelled out per mode: preview when the user asks what is shared, sync only when the user asks to send now. It also names what this tool is NOT for (changing choices) and where that happens instead (dashboard Settings, Data sharing).

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

freeapply_update_jobUpdate a job's application statusA
DestructiveIdempotent

Sets a claimed job's status: your side of the application (employer's response: freeapply_record_outcome; adding a job: freeapply_claim_job). Use: after a submit (applied); giving up (skipped, failed); when the user must act: needs_info with the form's questions, needs_account with the sign-up page, blocked by a check you can't pass. Behavior: replaces the status. Enforced: applied needs a fresh freeapply_clear_to_submit clearance for this job; cover_text must pass the truthfulness check; an applied job only the user can change. needs_info questions go to the Needs you tab and re-queue the job once answered; if the user already answered them all, refused with the answers to use. A field marked for one status is refused with any other. Returns: {job_id, status} and when relevant: already_waiting; questions (each added, duplicate, grouped or already_answered, with its answer), questions_added; same_account (needs_account: jobs sharing one sign-up card); same_site (blocked: jobs blocked on the same site). Errors: an unknown job_id or a broken rule, saying what is missing.

NameRequiredDescriptionDefault
noteNoWhat happened, for the user: one plain sentence, no technical terms, e.g. "The site asked to prove you're a person."
job_idYesThe job's id, as returned by freeapply_claim_job or freeapply_list_jobs.
methodNoapplied only: how it was submitted.
statusYesNew status: found (qualified, not yet worked), ready (documents prepared, not yet submitted), applied (application submitted), skipped (filtered out (see status_note)), needs_info (a form asked something the profile does not answer), needs_account (employer site requires creating an account), blocked (CAPTCHA, verification code or site warning), failed (error while applying).
questionsNoneeds_info only, at least one: the form's unanswered questions, each with a plain prompt and the simplest kind of answer that fits.
cover_pathNoapplied only: the letter file sent, if not the saved one.
cover_textNoapplied only: the letter sent, if not the saved one.
account_urlNoneeds_account only: the site's sign-up page. Jobs with the same one share a card; one "I made the account" re-queues them all. Default: the application link, so jobs rarely share.
letter_sentNoapplied only; required when a letter is saved for the job (freeapply_check_text save): true if attached or pasted, false if not (letter dropped from the record).
resume_pathNoapplied only: the résumé file sent, if not the documents copy (recorded by default).
confirmationNoapplied only: the confirmation text or number the site showed.

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond annotations, the description discloses key behavior: status replacement, fresh clearance enforcement for applied, truthfulness checks on cover_text, the rule that applied jobs only the user can change, needs_info re-queue behavior, and refusal rules for status-specific fields. It also describes return fields and error conditions, giving the agent operational context needed to invoke it safely.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded and organized into clear Use, Behavior, Returns, and Errors sections. Despite its length, every section earns its place by covering a complex multi-status tool with 11 parameters.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

There is no output schema, but the description supplies the relevant return shape and error behavior. Combined with annotations and full schema coverage, it gives enough information for an agent to call the tool correctly across statuses and edge cases.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already carries most parameter meaning and baseline is 3. The description adds conditional semantics beyond the schema, such as applied-only enforcement, needs_info question handling, needs_account sign-up page behavior, and refusal when a field is supplied for the wrong status.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description gives a specific verb and resource: it sets a claimed job's application status. It immediately distinguishes the tool from siblings by naming freeapply_record_outcome for employer responses and freeapply_claim_job for adding jobs, so an agent can identify the correct tool without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explicitly maps statuses to situations: applied after submit, skipped/failed when giving up, needs_info/needs_account/blocked when the user must act. It also names alternative tools for adjacent operations, leaving little ambiguity about when to use this tool versus siblings.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

freeapply_update_settingsSave settings and résuméA
DestructiveIdempotent

Changes the user's settings: facts and preferences the user states, the résumé's text and profile (setup), and the AI models scan. Reading: freeapply_get_settings; single form answers: freeapply_manage_answers. Use: when the user states a fact or preference, in setup's résumé step, in the AI models step. Never fill a field the user didn't give you. Behavior: overwrites the sent fields, no undo. Deep merge: only sent fields change, nested objects merge, lists are replaced whole. User-only sections (legal, sharing, automation, autorun, onboarding, integrity, model_choices) are skipped and listed in ignored. All or nothing: one wrong field saves nothing. Parameters: patch, nested by section with the names freeapply_get_settings returns, e.g. {"targets": {"min_pay": 60000}}. Writable: profile, targets, eligibility, cover_letter, custom_answers (one at a time: freeapply_manage_answers), gmail (not last_check or manual_logins); resume only text and profile {headline, skills, titles, education, certifications}, taken from the résumé text alone; models only the scan {app, current, can_delegate, available, efforts}, read from your own tools, which replaces the last one. Returns: {changed, ignored, setup_complete, missing}; after a scan also models (model and effort chosen per level). Errors: nothing writable, unknown section or field, wrong type, value outside its choices (e.g. cover_letter.length short|standard|long), résumé files (the user adds them in the dashboard), malformed scan; the message names every problem.

NameRequiredDescriptionDefault
patchYesFields to change, nested by section.

TDQS

A5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already mark it destructive and idempotent, and the description adds substantial operational context: overwrites without undo, deep-merge semantics, whole-list replacement, skipped user-only sections listed in ignored, and all-or-nothing saves. It also describes error behavior where the message names every problem.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

It is dense but organized into clear operational clauses: Changes, Use, Behavior, Parameters, Returns, and Errors. The purpose and usage are front-loaded, and each section carries distinct information needed for a complex nested update tool rather than repeating structured fields.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a destructive nested update tool with no output schema, the description covers return fields (changed, ignored, setup_complete, missing, and models after a scan) and the main error cases. Combined with merge and skipped-section behavior, it is complete enough for an agent to invoke it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema only says patch is an object nested by section. The description supplies the actual section names, an example patch, the writable fields, résumé and model-scan restrictions, and validation constraints such as cover_letter.length choices, which is far beyond what the schema provides.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States the specific resource (user settings) and the three content areas it saves: stated facts/preferences, résumé text and profile, and the AI model scan. It also names freeapply_get_settings for reading and freeapply_manage_answers for single form answers, distinguishing it from those siblings.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly says when to use it: when the user states a fact or preference, during setup's résumé step, or in the AI models step. It also gives a clear when-not rule: never fill a field the user did not provide, and routes reading to freeapply_get_settings and single answers to freeapply_manage_answers.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 20 tool updatesv1.0.6
    • Removedfreeapply_autorun
    • Addedfreeapply_check_replies
    • Changedfreeapply_clear_to_submit3 fields changed
      • changedInput schema / properties / job_id / description
        Previous value: -"The job about to be submitted; without it you only see the pace."New value: +"The job about to be submitted."
      • changedInput schema / properties / method / description
        Previous value: -"How you will submit: external (employer or ATS form; default), easy_apply (a job board's one-click apply; refused while one-click apply is off) or email."New value: +"How you will submit (default external)."
      • changedInput schema / properties / run_id / description
        Previous value: -"Unattended run only: the run_id from freeapply_autorun start; first checks that run's limits and the dashboard's Stop button, and keeps the run alive."New value: +"Auto-run only: the run_id from freeapply_manage_autorun start."
    • Changedfreeapply_fetch_posting1 field changed
      • changedInput schema / properties / source / description
        Previous value: -"Job site id where found, e.g. linkedin; picks the saved answers meant for that site."New value: +"Job site id where found, e.g. linkedin."
    • Changedfreeapply_find_site_account1 field changed
      • changedInput schema / properties / site / description
        Previous value: -"Domain or any URL on it, e.g. careers.example.com; reduced to the domain without www. and matched exactly (careers.example.com and example.com differ)."New value: +"Domain or any URL on it, e.g. careers.example.com."
    • Changedfreeapply_get_settings1 field changed
      • changedInput schema / properties / sections / description
        Previous value: -"Sections to return (default all), e.g. [\"profile\", \"eligibility\"] for a form; omit resume, the largest, unless you need its text."New value: +"Section names to return (default all)."
    • Addedfreeapply_get_stats
    • Addedfreeapply_get_status
    • Removedfreeapply_job_stats
    • Changedfreeapply_list_jobs4 fields changed
      • addedInput schema / properties / job_id
        Added value: +{
        +  "description": "One job by its id.",
        +  "minimum": 1,
        +  "type": "integer"
        +}
      • changedInput schema / properties / limit / description
        Previous value: -"Most jobs to return (default 200); fewer returned means the end."New value: +"Most jobs to return (default 200)."
      • changedInput schema / properties / offset / description
        Previous value: -"Jobs to skip, for the next page (default 0)."New value: +"Jobs to skip (default 0)."
      • changedInput schema / properties / search / description
        Previous value: -"Text in the title, company or location, ignoring case."New value: +"Text to find."
    • Addedfreeapply_manage_answers
    • Addedfreeapply_manage_autorun
    • Changedfreeapply_open_dashboard1 field changed
      • changedInput schema / properties / tab / description
        Previous value: -"Page: overview (default; shows the Terms until accepted), settings (setup fields), issues (Needs you: questions, sign-ups), applications, replies."New value: +"The page to open (default overview)."
    • Removedfreeapply_reply_check
    • Changedfreeapply_report_site_problem1 field changed
      • changedInput schema / properties / site / description
        Previous value: -"Job site id, as freeapply_status lists it in sites."New value: +"Job site id, as freeapply_get_status lists it in sites."
    • Addedfreeapply_share_data
    • Removedfreeapply_shared_data
    • Removedfreeapply_status
    • Changedfreeapply_update_settings1 field changed
      • changedInput schema / properties / patch / description
        Previous value: -"Fields to change, nested by section with freeapply_get_settings' names, e.g. {\"targets\": {\"min_pay\": 60000}}. resume: only text and profile {headline, skills, titles, education, certifications}, from the résumé text alone. models: the scan {app, current, can_delegate, available, efforts}, read from your own tools; replaces the last scan."New value: +"Fields to change, nested by section."
    • Removedfreeapply_user_answers
  2. 2 tool updatesv1.0.5
    • Changedfreeapply_autorun1 field changed
      • addedInput schema / properties / wait
        Added value: +{
        +  "description": "For start, in a scheduled run: if the user turned auto-run off, wait for them to press Start.",
        +  "type": "boolean"
        +}
    • Changedfreeapply_clear_to_submit1 field changed
      • changedInput schema / properties / run_id / description
        Previous value: -"Unattended run only: the run_id from freeapply_autorun start; first checks that run's time and application budgets and the dashboard's Stop button."New value: +"Unattended run only: the run_id from freeapply_autorun start; first checks that run's limits and the dashboard's Stop button, and keeps the run alive."
  3. 17 tool updatesv1.0.4
    • Changedfreeapply_autorun3 fields changed
      • changedInput schema / properties / action / description
        Previous value: -"start or finish a run, or report the scheduled task."New value: +"start or finish a run; schedule_created or schedule_removed report the scheduled task."
      • changedInput schema / properties / run_id / description
        Previous value: -"For finish: the run_id that start returned."New value: +"Required for finish: the run_id start returned."
      • changedInput schema / properties / summary / description
        Previous value: -"For finish: one line on the run."New value: +"For finish: one line on the run, e.g. \"applied 4, needs you 2\" (up to 500 characters)."
    • Changedfreeapply_check_text5 fields changed
      • changedInput schema / properties / company / description
        Previous value: -"The employer, when there is no job_id. Optional."New value: +"The employer, when there is no job_id."
      • changedInput schema / properties / job_id / description
        Previous value: -"The job it is for. Optional; needed for save."New value: +"Adds the posting's keywords; numbers from the job's posting, title, pay, location and posting id, and the user's answers for this job, count as facts. Needed for save."
      • changedInput schema / properties / kind / description
        Previous value: -"What the text is. Optional; default answer."New value: +"cover_letter: also checks the user's length, sign-off, leftover placeholders and that the company is named. answer (default): facts only."
      • changedInput schema / properties / save / description
        Previous value: -"Save a passing cover letter as a PDF. Optional; default false."New value: +"Save a passing cover letter as a PDF (default false). For a letter, pass it from the first call: checked and saved at once."
      • changedInput schema / properties / text / description
        Previous value: -"The cover letter or answer to check, exactly as you will type or attach it."New value: +"The letter or answer, exactly as you will type or attach it."
    • Changedfreeapply_claim_job13 fields changed
      • changedInput schema / properties / apply_url / description
        Previous value: -"Where the application form is, if different."New value: +"Application form URL, if different."
      • changedInput schema / properties / company / description
        Previous value: -"Employer name, as posted (not the staffing firm's name, if known)."New value: +"The employer as posted; not a staffing firm, when you can tell."
      • changedInput schema / properties / external_id / description
        Previous value: -"The posting's id on its source site; finds the same posting again, reposts included."New value: +"The posting's id on its source site; pass it whenever shown: finds the posting again and catches reposts."
      • changedInput schema / properties / fit_notes / description
        Previous value: -"Why it fits or doesn't, in one sentence."New value: +"Why it fits or doesn't, one sentence."
      • changedInput schema / properties / fit_score / description
        Previous value: -"Fit from 0 to 100, scored as the apply procedure describes."New value: +"0-100, scored as the apply procedure says."
      • changedInput schema / properties / location / description
        Previous value: -"Location as posted."New value: +"As posted."
      • changedInput schema / properties / pay_max / description
        Previous value: -"Highest posted pay as a number."New value: +"Highest posted pay, a number. Feeds the pay floor."
      • changedInput schema / properties / pay_min / description
        Previous value: -"Lowest posted pay as a number: annual, or hourly if posted hourly."New value: +"Lowest posted pay, a number: annual, or hourly if posted hourly. Feeds the pay floor."
      • changedInput schema / properties / source / description
        Previous value: -"Where it was found: a job site id (linkedin, indeed, company_sites, ...) or referral."New value: +"Where found: job site id (linkedin, indeed, company_sites, ...) or referral; tells the job site like url."
      • changedInput schema / properties / status / description
        Previous value: -"found to work on it (default), or skipped to record a job you won't pursue."New value: +"found (default): to work on; skipped: a job you won't pursue."
      • changedInput schema / properties / status_note / description
        Previous value: -"Why it was skipped, in one plain sentence; for status skipped."New value: +"For skipped: why, one plain sentence."
      • changedInput schema / properties / title / description
        Previous value: -"Job title, as posted."New value: +"As posted."
      • changedInput schema / properties / url / description
        Previous value: -"The posting's URL; also tells which job site it came from."New value: +"Posting URL; tells the job site. The URL just read by freeapply_fetch_posting keeps its keywords."
    • Changedfreeapply_clear_to_submit3 fields changed
      • changedInput schema / properties / job_id / description
        Previous value: -"The job about to be submitted."New value: +"The job about to be submitted; without it you only see the pace."
      • changedInput schema / properties / method / description
        Previous value: -"How you will submit: external (an employer or ATS form; default), easy_apply (a job board's one-click apply) or email."New value: +"How you will submit: external (employer or ATS form; default), easy_apply (a job board's one-click apply; refused while one-click apply is off) or email."
      • changedInput schema / properties / run_id / description
        Previous value: -"In an unattended run only: the run_id that freeapply_autorun start returned."New value: +"Unattended run only: the run_id from freeapply_autorun start; first checks that run's time and application budgets and the dashboard's Stop button."
    • Changedfreeapply_fetch_posting3 fields changed
      • changedInput schema / properties / max_chars / description
        Previous value: -"Longest description to return, in characters. Optional; default 6000."New value: +"Description cap in characters (default 6000)."
      • changedInput schema / properties / source / description
        Previous value: -"The job site id where it was found. Optional."New value: +"Job site id where found, e.g. linkedin; picks the saved answers meant for that site."
      • changedInput schema / properties / url / description
        Previous value: -"The posting's URL: the job page or its application form."New value: +"The job page or its application form."
    • Changedfreeapply_find_site_account1 field changed
      • changedInput schema / properties / site / description
        Previous value: -"The employer site's domain or any URL on it, e.g. careers.example.com."New value: +"Domain or any URL on it, e.g. careers.example.com; reduced to the domain without www. and matched exactly (careers.example.com and example.com differ)."
    • Changedfreeapply_get_settings1 field changed
      • changedInput schema / properties / sections / description
        Previous value: -"Sections to return. Optional; default all."New value: +"Sections to return (default all), e.g. [\"profile\", \"eligibility\"] for a form; omit resume, the largest, unless you need its text."
    • Changedfreeapply_list_jobs5 fields changed
      • changedInput schema / properties / limit / description
        Previous value: -"Most jobs to return. Optional; default 200."New value: +"Most jobs to return (default 200); fewer returned means the end."
      • changedInput schema / properties / offset / description
        Previous value: -"Jobs to skip, for the next page. Optional; default 0."New value: +"Jobs to skip, for the next page (default 0)."
      • changedInput schema / properties / outcome / description
        Previous value: -"Only jobs with this employer outcome. Optional."New value: +"Exact employer-outcome filter."
      • changedInput schema / properties / search / description
        Previous value: -"Text to find in the title, company or location. Optional."New value: +"Text in the title, company or location, ignoring case."
      • changedInput schema / properties / status / description
        Previous value: -"Only jobs with this status. Optional."New value: +"Exact status filter."
    • Changedfreeapply_open_dashboard1 field changed
      • changedInput schema / properties / tab / description
        Previous value: -"The page to open. Optional; default overview."New value: +"Page: overview (default; shows the Terms until accepted), settings (setup fields), issues (Needs you: questions, sign-ups), applications, replies."
    • Changedfreeapply_record_outcome9 fields changed
      • changedInput schema / properties / company / description
        Previous value: -"With an email: the employer that sent it."New value: +"Email: the employer that sent it."
      • changedInput schema / properties / gmail_thread_id / description
        Previous value: -"With an email: Gmail thread id."New value: +"Email: Gmail thread id."
      • changedInput schema / properties / job_id / description
        Previous value: -"The job it is about."New value: +"From the reply-check plan or freeapply_list_jobs. Required without an email; with one optional, but without it no outcome changes."
      • changedInput schema / properties / mail_action / description
        Previous value: -"With an email: what you did with it in Gmail."New value: +"Email: what you did with it in Gmail: starred, labeled:<name>, starred+labeled:<name> or none."
      • changedInput schema / properties / outcome / description
        Previous value: -"What the employer did: acknowledged (automatic 'we received your application' email), replied (a person replied), assessment (test, assignment or screening questionnaire), interview (interview requested or scheduled), rejected (rejection), offer (offer), withdrawn (candidate withdrew); or \"\" to clear it."New value: +"What the employer did: acknowledged (automatic 'we received your application' email), replied (a person replied), assessment (test, assignment or screening questionnaire), interview (interview requested or scheduled), rejected (rejection), offer (offer), withdrawn (candidate withdrew); or \"\" to clear it (without an email only)."
      • changedInput schema / properties / received_at / description
        Previous value: -"With an email: when it arrived (ISO 8601)."New value: +"Email: when it arrived (ISO 8601)."
      • changedInput schema / properties / sender / description
        Previous value: -"With an email: sender address."New value: +"Email: sender address."
      • changedInput schema / properties / subject / description
        Previous value: -"With an email: subject line."New value: +"Email: subject line."
      • changedInput schema / properties / summary / description
        Previous value: -"With an email: one sentence on what it says."New value: +"Email: what it says, one sentence of at most 20 words, no personal data beyond what is needed."
    • Changedfreeapply_reply_check4 fields changed
      • changedInput schema / properties / action / description
        Previous value: -"start returns the plan; finish marks the check done."New value: +"start: the plan; read: the mailbox; mark: star or label one email; finish: the check is done."
      • changedInput schema / properties / action / enum
        Previous value: -[
        -  "start",
        -  "finish"
        -]New value: +[
        +  "start",
        +  "read",
        +  "mark",
        +  "finish"
        +]
      • addedInput schema / properties / gmail_message_id
        Added value: +{
        +  "description": "Required for mark: the email's id, from read.",
        +  "type": "string"
        +}
      • addedInput schema / properties / kind
        Added value: +{
        +  "description": "Required for mark: the outcome you recorded for the email.",
        +  "enum": [
        +    "acknowledged",
        +    "replied",
        +    "assessment",
        +    "interview",
        +    "rejected",
        +    "offer",
        +    "withdrawn"
        +  ],
        +  "type": "string"
        +}
    • Changedfreeapply_report_site_problem2 fields changed
      • changedInput schema / properties / site / description
        Previous value: -"The job site, as listed in freeapply_status sites."New value: +"Job site id, as freeapply_status lists it in sites."
      • changedInput schema / properties / status / description
        Previous value: -"What the site showed."New value: +"signed_out: a sign-in page, or the site says you're signed out. limit_reached: the site's own daily limit, e.g. \"You reached today's Easy Apply limit\"."
    • Changedfreeapply_shared_data1 field changed
      • changedInput schema / properties / action / description
        Previous value: -"preview shows what would be sent; sync sends it now."New value: +"preview: show what would be sent; sync: send it now."
    • Changedfreeapply_status2 fields changed
      • addedInput schema / properties / lane
        Added value: +{
        +  "description": "A helper's lane of freeapply-apply: only the hard rules and that lane's steps, with a short status. Optional; the agent that starts helpers omits it.",
        +  "enum": [
        +    "scout",
        +    "writer",
        +    "applier"
        +  ],
        +  "type": "string"
        +}
      • changedInput schema / properties / procedure / description
        Previous value: -"The task whose procedure to include. Optional."New value: +"Adds this task's procedure: freeapply-setup (first run; Terms or settings missing), freeapply-apply (find jobs, apply), freeapply-replies (Gmail reply check). Omit for status only."
    • Changedfreeapply_update_job13 fields changed
      • changedInput schema / properties / account_url / description
        Previous value: -"For needs_account: the site's sign-up page. Jobs with the same one share a card, and one \"I made the account\" re-queues them all; without it the application link is used, so jobs rarely share."New value: +"needs_account only: the site's sign-up page. Jobs with the same one share a card; one \"I made the account\" re-queues them all. Default: the application link, so jobs rarely share."
      • changedInput schema / properties / confirmation / description
        Previous value: -"For applied: the confirmation text or number the site showed."New value: +"applied only: the confirmation text or number the site showed."
      • changedInput schema / properties / cover_path / description
        Previous value: -"For applied: the cover-letter file sent, if not the saved one. Optional."New value: +"applied only: the letter file sent, if not the saved one."
      • changedInput schema / properties / cover_text / description
        Previous value: -"For applied: the cover letter sent, if not the saved one. Optional."New value: +"applied only: the letter sent, if not the saved one."
      • addedInput schema / properties / letter_sent
        Added value: +{
        +  "description": "applied only; required when a letter is saved for the job (freeapply_check_text save): true if attached or pasted, false if not (letter dropped from the record).",
        +  "type": "boolean"
        +}
      • changedInput schema / properties / method / description
        Previous value: -"For applied: how it was submitted."New value: +"applied only: how it was submitted."
      • changedInput schema / properties / note / description
        Previous value: -"What happened, for the user, e.g. \"The site asked to prove you're a person.\""New value: +"What happened, for the user: one plain sentence, no technical terms, e.g. \"The site asked to prove you're a person.\""
      • changedInput schema / properties / questions / description
        Previous value: -"For needs_info: the form's unanswered questions, each with a plain prompt and the simplest kind of answer that fits."New value: +"needs_info only, at least one: the form's unanswered questions, each with a plain prompt and the simplest kind of answer that fits."
      • changedInput schema / properties / questions / items / properties / label / description
        Previous value: -"The question exactly as the form words it (you need it to fill the form later)."New value: +"Exactly as the form words it (needed to fill the form later)."
      • changedInput schema / properties / questions / items / properties / options / description
        Previous value: -"Choices, for choice or multi, worded as the form offers them."New value: +"For choice or multi: the choices as the form words them."
      • changedInput schema / properties / questions / items / properties / prompt / description
        Previous value: -"The question in plain words for the user: one short sentence, no form codes or jargon, e.g. \"Can you work weekends?\" for \"Availability - Sat/Sun shifts (Y/N)*\"."New value: +"Plain words for the user: one short sentence, no form codes or jargon, e.g. \"Can you work weekends?\" for \"Availability - Sat/Sun shifts (Y/N)*\"."
      • changedInput schema / properties / questions / items / properties / type / description
        Previous value: -"Kind of answer: yesno or choice for fixed answers (one; buttons up to 5 options, a dropdown for more), multi (all that apply), number, date, or text or textarea."New value: +"yesno or choice: one fixed answer (buttons up to 5 options, else a dropdown); multi: all that apply; number; date; text or textarea."
      • changedInput schema / properties / resume_path / description
        Previous value: -"For applied: the résumé file sent, if not the documents copy. Optional."New value: +"applied only: the résumé file sent, if not the documents copy (recorded by default)."
    • Changedfreeapply_update_settings1 field changed
      • changedInput schema / properties / patch / description
        Previous value: -"The fields to change, nested by section, e.g. {\"profile\": {\"phone\": \"+1 555 0100\"}}."New value: +"Fields to change, nested by section with freeapply_get_settings' names, e.g. {\"targets\": {\"min_pay\": 60000}}. resume: only text and profile {headline, skills, titles, education, certifications}, from the résumé text alone. models: the scan {app, current, can_delegate, available, efforts}, read from your own tools; replaces the last scan."
    • Changedfreeapply_user_answers4 fields changed
      • changedInput schema / properties / action / description
        Previous value: -"get a job's answers, or save one reusable answer."New value: +"get: a job's answers and saved letter; save: one reusable answer."
      • changedInput schema / properties / answer / description
        Previous value: -"For save: the user's answer in their own words; empty to remove a saved answer."New value: +"For save: the user's own words; empty removes the saved answer."
      • changedInput schema / properties / job_id / description
        Previous value: -"For get: the job whose answers you need."New value: +"Required for get."
      • changedInput schema / properties / label / description
        Previous value: -"For save: the question, worded as forms ask it, e.g. \"Are you willing to relocate?\"."New value: +"Required for save: the question as forms word it, e.g. \"Are you willing to relocate?\"."
  4. 26 tool updatesv1.0.2
    • Removedfreeapply_add_job
    • Removedfreeapply_answers
    • Changedfreeapply_autorun4 fields changed
      • changedInput schema / properties / action / description
        Previous value: -"What to do."New value: +"start or finish a run, or report the scheduled task."
      • changedInput schema / properties / action / enum
        Previous value: -[
        -  "start",
        -  "check",
        -  "finish",
        -  "schedule_created",
        -  "schedule_removed"
        -]New value: +[
        +  "start",
        +  "finish",
        +  "schedule_created",
        +  "schedule_removed"
        +]
      • changedInput schema / properties / run_id / description
        Previous value: -"The run_id that start returned; needed for check and finish."New value: +"For finish: the run_id that start returned."
      • changedInput schema / properties / summary / description
        Previous value: -"One-line summary, for finish."New value: +"For finish: one line on the run."
    • Removedfreeapply_check_duplicate
    • Changedfreeapply_check_text4 fields changed
      • changedInput schema / properties / company / description
        Previous value: -"The employer it is addressed to. Optional; a cover letter that never mentions it is flagged."New value: +"The employer, when there is no job_id. Optional."
      • changedInput schema / properties / job_id / description
        Previous value: -"The job it is for. Optional; numbers from its posting and the user's answers for it then count as supported."New value: +"The job it is for. Optional; needed for save."
      • addedInput schema / properties / save
        Added value: +{
        +  "description": "Save a passing cover letter as a PDF. Optional; default false.",
        +  "type": "boolean"
        +}
      • changedInput schema / properties / text / description
        Previous value: -"The cover letter or answer to check."New value: +"The cover letter or answer to check, exactly as you will type or attach it."
    • Addedfreeapply_claim_job
    • Addedfreeapply_clear_to_submit
    • Changedfreeapply_fetch_posting1 field changed
      • changedInput schema / properties / source / description
        Previous value: -"Where the posting was found, as a job site id (linkedin, indeed, company_sites, ...). Optional; helps pick suggested answers."New value: +"The job site id where it was found. Optional."
    • Addedfreeapply_find_site_account
    • Changedfreeapply_get_settings1 field changed
      • addedInput schema / properties / sections
        Added value: +{
        +  "description": "Sections to return. Optional; default all.",
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
    • Removedfreeapply_get_stats
    • Addedfreeapply_job_stats
    • Changedfreeapply_open_dashboard1 field changed
      • changedInput schema / properties / tab / description
        Previous value: -"Tab to show. Optional; default overview."New value: +"The page to open. Optional; default overview."
    • Addedfreeapply_record_outcome
    • Removedfreeapply_record_reply
    • Addedfreeapply_report_site_problem
    • Removedfreeapply_save_resume
    • Removedfreeapply_set_outcome
    • Removedfreeapply_site_account
    • Removedfreeapply_site_status
    • Changedfreeapply_status1 field changed
      • addedInput schema / properties / procedure
        Added value: +{
        +  "description": "The task whose procedure to include. Optional.",
        +  "enum": [
        +    "freeapply-setup",
        +    "freeapply-apply",
        +    "freeapply-replies"
        +  ],
        +  "type": "string"
        +}
    • Removedfreeapply_throttle
    • Changedfreeapply_update_job10 fields changed
      • changedInput schema / properties / account_url / description
        Previous value: -"For needs_account: the full link to the page where the user makes the account (the site's sign-up page). Jobs whose account is made at the same address share one card, and one \"I made the account\" re-queues them all; without it the application link is used, so jobs rarely share."New value: +"For needs_account: the site's sign-up page. Jobs with the same one share a card, and one \"I made the account\" re-queues them all; without it the application link is used, so jobs rarely share."
      • changedInput schema / properties / confirmation / description
        Previous value: -"Confirmation text or number the site showed."New value: +"For applied: the confirmation text or number the site showed."
      • changedInput schema / properties / cover_path / description
        Previous value: -"Path of the cover-letter file submitted."New value: +"For applied: the cover-letter file sent, if not the saved one. Optional."
      • changedInput schema / properties / cover_text / description
        Previous value: -"The cover letter actually submitted; it must pass the truthfulness check."New value: +"For applied: the cover letter sent, if not the saved one. Optional."
      • changedInput schema / properties / job_id / description
        Previous value: -"The job's id, as returned by freeapply_add_job or freeapply_list_jobs."New value: +"The job's id, as returned by freeapply_claim_job or freeapply_list_jobs."
      • changedInput schema / properties / method / description
        Previous value: -"How it was submitted, for applied."New value: +"For applied: how it was submitted."
      • changedInput schema / properties / note / description
        Previous value: -"What happened, in one plain sentence the user will read on the dashboard: no code, page elements or technical terms, e.g. \"The site asked to prove you're a person.\""New value: +"What happened, for the user, e.g. \"The site asked to prove you're a person.\""
      • changedInput schema / properties / questions / description
        Previous value: -"For needs_info: the form's unanswered questions. Give each a plain prompt and the simplest kind of answer that fits: a choice with options (or yesno) when the form offers fixed answers, multi when it takes several, text otherwise."New value: +"For needs_info: the form's unanswered questions, each with a plain prompt and the simplest kind of answer that fits."
      • changedInput schema / properties / questions / items / properties / type / description
        Previous value: -"Kind of answer: text or textarea (open-ended, short or long), yesno, choice (pick one; buttons for up to 5 options, a dropdown for more), multi (pick all that apply), number or date."New value: +"Kind of answer: yesno or choice for fixed answers (one; buttons up to 5 options, a dropdown for more), multi (all that apply), number, date, or text or textarea."
      • changedInput schema / properties / resume_path / description
        Previous value: -"Path of the résumé file submitted."New value: +"For applied: the résumé file sent, if not the documents copy. Optional."
    • Changedfreeapply_update_settings1 field changed
      • changedInput schema / properties / patch / description
        Previous value: -"The fields to change, nested by section, e.g. {\"targets\": {\"min_pay\": 60000, \"locations\": [\"Denver, CO\"]}} or {\"profile\": {\"phone\": \"+1 555 0100\"}}. Field names are as freeapply_get_settings returns them."New value: +"The fields to change, nested by section, e.g. {\"profile\": {\"phone\": \"+1 555 0100\"}}."
    • Addedfreeapply_user_answers
    • Removedfreeapply_workflow
  5. 26 tool updatesv1.0.1
    • Changedfreeapply_add_job19 fields changed
      • addedInput schema / properties / apply_url / description
        Added value: +"Where the application form is, if different."
      • addedInput schema / properties / company / description
        Added value: +"Employer name."
      • addedInput schema / properties / description / description
        Added value: +"Short description or key requirements."
      • changedInput schema / properties / external_id / description
        Previous value: -"posting id on the source site"New value: +"The posting's id on its source site, used to spot reposts."
      • addedInput schema / properties / fit_notes / description
        Added value: +"Why it fits or doesn't, in a sentence."
      • addedInput schema / properties / fit_score / description
        Added value: +"Fit from 0 to 100, as the procedure describes."
      • addedInput schema / properties / fit_score / maximum
        Added value: +100
      • addedInput schema / properties / fit_score / minimum
        Added value: +0
      • addedInput schema / properties / location / description
        Added value: +"Location as posted."
      • addedInput schema / properties / pay_max / description
        Added value: +"Highest posted pay as a number."
      • addedInput schema / properties / pay_min / description
        Added value: +"Lowest posted pay as a number (annual, or hourly if posted hourly)."
      • addedInput schema / properties / pay_text / description
        Added value: +"Pay exactly as posted, e.g. \"$90k-$110k\"."
      • changedInput schema / properties / source / description
        Previous value: -"linkedin, company_site, indeed, referral, ..."New value: +"Where it was found: a job site id (linkedin, indeed, company_sites, ...) or referral."
      • addedInput schema / properties / status / description
        Added value: +"found to work on it (default), skipped to record a job that doesn't fit."
      • addedInput schema / properties / status / enum
        Added value: +[
        +  "found",
        +  "skipped"
        +]
      • addedInput schema / properties / status_note / description
        Added value: +"Reason, for a skipped job."
      • addedInput schema / properties / title / description
        Added value: +"Job title."
      • addedInput schema / properties / url / description
        Added value: +"The posting's URL."
      • addedInput schema / properties / work_mode / description
        Added value: +"remote, hybrid or onsite, as posted."
    • Addedfreeapply_answers
    • Changedfreeapply_autorun4 fields changed
      • addedInput schema / properties / action / description
        Added value: +"What to do."
      • addedInput schema / properties / action / enum
        Added value: +[
        +  "start",
        +  "check",
        +  "finish",
        +  "schedule_created",
        +  "schedule_removed"
        +]
      • addedInput schema / properties / run_id / description
        Added value: +"The run_id that start returned; needed for check and finish."
      • addedInput schema / properties / summary / description
        Added value: +"One-line summary, for finish."
    • Changedfreeapply_check_duplicate3 fields changed
      • addedInput schema / properties / company / description
        Added value: +"Employer name as shown in the posting."
      • addedInput schema / properties / external_id / description
        Added value: +"The posting's id on its source site. Optional; also finds the exact posting."
      • addedInput schema / properties / title / description
        Added value: +"Job title. Optional; marks matches with the same title."
    • Changedfreeapply_check_text6 fields changed
      • addedInput schema / properties / company / description
        Added value: +"The employer it is addressed to. Optional; a cover letter that never mentions it is flagged."
      • addedInput schema / properties / job_id / description
        Added value: +"The job it is for. Optional; numbers from its posting and the user's answers for it then count as supported."
      • addedInput schema / properties / job_id / minimum
        Added value: +1
      • addedInput schema / properties / kind / description
        Added value: +"What the text is. Optional; default answer."
      • addedInput schema / properties / kind / enum
        Added value: +[
        +  "cover_letter",
        +  "answer"
        +]
      • addedInput schema / properties / text / description
        Added value: +"The cover letter or answer to check."
    • Changedfreeapply_fetch_posting5 fields changed
      • addedInput schema / properties / max_chars / default
        Added value: +6000
      • addedInput schema / properties / max_chars / description
        Added value: +"Longest description to return, in characters. Optional; default 6000."
      • addedInput schema / properties / max_chars / minimum
        Added value: +500
      • addedInput schema / properties / source / description
        Added value: +"Where the posting was found, as a job site id (linkedin, indeed, company_sites, ...). Optional; helps pick suggested answers."
      • addedInput schema / properties / url / description
        Added value: +"The posting's URL: the job page or its application form."
    • Removedfreeapply_finish_reply_check
    • Removedfreeapply_get_answers
    • Changedfreeapply_list_jobs10 fields changed
      • addedInput schema / properties / limit / default
        Added value: +200
      • addedInput schema / properties / limit / description
        Added value: +"Most jobs to return. Optional; default 200."
      • addedInput schema / properties / limit / maximum
        Added value: +2000
      • addedInput schema / properties / limit / minimum
        Added value: +1
      • addedInput schema / properties / offset
        Added value: +{
        +  "default": 0,
        +  "description": "Jobs to skip, for the next page. Optional; default 0.",
        +  "minimum": 0,
        +  "type": "integer"
        +}
      • addedInput schema / properties / outcome / description
        Added value: +"Only jobs with this employer outcome. Optional."
      • addedInput schema / properties / outcome / enum
        Added value: +[
        +  "acknowledged",
        +  "replied",
        +  "assessment",
        +  "interview",
        +  "rejected",
        +  "offer",
        +  "withdrawn"
        +]
      • addedInput schema / properties / search / description
        Added value: +"Text to find in the title, company or location. Optional."
      • addedInput schema / properties / status / description
        Added value: +"Only jobs with this status. Optional."
      • addedInput schema / properties / status / enum
        Added value: +[
        +  "found",
        +  "ready",
        +  "applied",
        +  "skipped",
        +  "needs_info",
        +  "needs_account",
        +  "blocked",
        +  "failed"
        +]
    • Changedfreeapply_open_dashboard2 fields changed
      • addedInput schema / properties / tab / description
        Added value: +"Tab to show. Optional; default overview."
      • addedInput schema / properties / tab / enum
        Added value: +[
        +  "overview",
        +  "applications",
        +  "replies",
        +  "issues",
        +  "settings"
        +]
    • Removedfreeapply_preview_shared_data
    • Changedfreeapply_record_reply12 fields changed
      • addedInput schema / properties / company / description
        Added value: +"The employer that sent it."
      • addedInput schema / properties / gmail_message_id / description
        Added value: +"Gmail message id; prevents recording it twice."
      • addedInput schema / properties / gmail_thread_id / description
        Added value: +"Gmail thread id."
      • addedInput schema / properties / job_id / description
        Added value: +"The job the email is about. Optional, but without it no outcome changes."
      • addedInput schema / properties / job_id / minimum
        Added value: +1
      • addedInput schema / properties / kind / description
        Added value: +"What the email is: acknowledged (automatic 'we received your application' email), replied (a person replied), assessment (test, assignment or screening questionnaire), interview (interview requested or scheduled), rejected (rejection), offer (offer), withdrawn (candidate withdrew)."
      • addedInput schema / properties / kind / enum
        Added value: +[
        +  "acknowledged",
        +  "replied",
        +  "assessment",
        +  "interview",
        +  "rejected",
        +  "offer",
        +  "withdrawn"
        +]
      • addedInput schema / properties / mail_action / description
        Added value: +"What you did with it in Gmail: starred, labeled:<name>, starred+labeled:<name> or none."
      • addedInput schema / properties / received_at / description
        Added value: +"When it arrived (ISO 8601)."
      • addedInput schema / properties / sender / description
        Added value: +"Sender address."
      • addedInput schema / properties / subject / description
        Added value: +"Subject line."
      • addedInput schema / properties / summary / description
        Added value: +"One sentence on what the email says (at most 20 words, no personal data beyond what is needed)."
    • Addedfreeapply_reply_check
    • Removedfreeapply_reply_check_plan
    • Addedfreeapply_save_resume
    • Removedfreeapply_save_resume_profile
    • Removedfreeapply_save_resume_text
    • Changedfreeapply_set_outcome4 fields changed
      • addedInput schema / properties / job_id / description
        Added value: +"The job's id, as returned by freeapply_add_job or freeapply_list_jobs."
      • addedInput schema / properties / job_id / minimum
        Added value: +1
      • addedInput schema / properties / outcome / description
        Added value: +"acknowledged (automatic 'we received your application' email), replied (a person replied), assessment (test, assignment or screening questionnaire), interview (interview requested or scheduled), rejected (rejection), offer (offer), withdrawn (candidate withdrew), or \"\" to clear."
      • addedInput schema / properties / outcome / enum
        Added value: +[
        +  "acknowledged",
        +  "replied",
        +  "assessment",
        +  "interview",
        +  "rejected",
        +  "offer",
        +  "withdrawn",
        +  ""
        +]
    • Addedfreeapply_shared_data
    • Changedfreeapply_site_account1 field changed
      • addedInput schema / properties / site / description
        Added value: +"The employer site's domain or any URL on it, e.g. careers.example.com or the application form's URL."
    • Changedfreeapply_site_status4 fields changed
      • changedInput schema / properties / site / description
        Previous value: -"linkedin, indeed, glassdoor, ziprecruiter, dice, wellfound, handshake, company_sites"New value: +"The job site."
      • addedInput schema / properties / site / enum
        Added value: +[
        +  "linkedin",
        +  "indeed",
        +  "glassdoor",
        +  "ziprecruiter",
        +  "dice",
        +  "wellfound",
        +  "handshake",
        +  "company_sites"
        +]
      • addedInput schema / properties / status / description
        Added value: +"What the site showed."
      • addedInput schema / properties / status / enum
        Added value: +[
        +  "signed_out",
        +  "limit_reached"
        +]
    • Removedfreeapply_sync_shared_data
    • Changedfreeapply_throttle4 fields changed
      • addedInput schema / properties / job_id / description
        Added value: +"The job's id, as returned by freeapply_add_job or freeapply_list_jobs."
      • addedInput schema / properties / job_id / minimum
        Added value: +1
      • addedInput schema / properties / method / description
        Added value: +"How you will submit. Optional; default external (an employer or ATS form)."
      • addedInput schema / properties / method / enum
        Added value: +[
        +  "external",
        +  "easy_apply",
        +  "email"
        +]
    • Changedfreeapply_update_job15 fields changed
      • addedInput schema / properties / account_url
        Added value: +{
        +  "description": "For needs_account: the full link to the page where the user makes the account (the site's sign-up page). Jobs whose account is made at the same address share one card, and one \"I made the account\" re-queues them all; without it the application link is used, so jobs rarely share.",
        +  "type": "string"
        +}
      • addedInput schema / properties / confirmation / description
        Added value: +"Confirmation text or number the site showed."
      • addedInput schema / properties / cover_path / description
        Added value: +"Path of the cover-letter file submitted."
      • addedInput schema / properties / cover_text / description
        Added value: +"The cover letter actually submitted; it must pass the truthfulness check."
      • addedInput schema / properties / job_id / description
        Added value: +"The job's id, as returned by freeapply_add_job or freeapply_list_jobs."
      • addedInput schema / properties / job_id / minimum
        Added value: +1
      • addedInput schema / properties / method / description
        Added value: +"How it was submitted, for applied."
      • addedInput schema / properties / method / enum
        Added value: +[
        +  "easy_apply",
        +  "external",
        +  "email"
        +]
      • addedInput schema / properties / note / description
        Added value: +"What happened, in one plain sentence the user will read on the dashboard: no code, page elements or technical terms, e.g. \"The site asked to prove you're a person.\""
      • addedInput schema / properties / questions / description
        Added value: +"For needs_info: the form's unanswered questions. Give each a plain prompt and the simplest kind of answer that fits: a choice with options (or yesno) when the form offers fixed answers, multi when it takes several, text otherwise."
      • addedInput schema / properties / questions / items / properties
        Added value: +{
        +  "help": {
        +    "description": "Optional one-line hint the user sees under the prompt: why it's asked or what a good answer looks like.",
        +    "type": "string"
        +  },
        +  "label": {
        +    "description": "The question exactly as the form words it (you need it to fill the form later).",
        +    "type": "string"
        +  },
        +  "options": {
        +    "description": "Choices, for choice or multi, worded as the form offers them.",
        +    "items": {
        +      "type": "string"
        +    },
        +    "type": "array"
        +  },
        +  "prompt": {
        +    "description": "The question in plain words for the user: one short sentence, no form codes or jargon, e.g. \"Can you work weekends?\" for \"Availability - Sat/Sun shifts (Y/N)*\".",
        +    "type": "string"
        +  },
        +  "required": {
        +    "description": "Whether the form requires it.",
        +    "type": "boolean"
        +  },
        +  "type": {
        +    "description": "Kind of answer: text or textarea (open-ended, short or long), yesno, choice (pick one; buttons for up to 5 options, a dropdown for more), multi (pick all that apply), number or date.",
        +    "enum": [
        +      "text",
        +      "textarea",
        +      "yesno",
        +      "choice",
        +      "multi",
        +      "number",
        +      "date"
        +    ],
        +    "type": "string"
        +  }
        +}
      • addedInput schema / properties / questions / items / required
        Added value: +[
        +  "label"
        +]
      • addedInput schema / properties / resume_path / description
        Added value: +"Path of the résumé file submitted."
      • addedInput schema / properties / status / description
        Added value: +"New status: found (qualified, not yet worked), ready (documents prepared, not yet submitted), applied (application submitted), skipped (filtered out (see status_note)), needs_info (a form asked something the profile does not answer), needs_account (employer site requires creating an account), blocked (CAPTCHA, verification code or site warning), failed (error while applying)."
      • addedInput schema / properties / status / enum
        Added value: +[
        +  "found",
        +  "ready",
        +  "applied",
        +  "skipped",
        +  "needs_info",
        +  "needs_account",
        +  "blocked",
        +  "failed"
        +]
    • Changedfreeapply_update_settings1 field changed
      • addedInput schema / properties / patch / description
        Added value: +"The fields to change, nested by section, e.g. {\"targets\": {\"min_pay\": 60000, \"locations\": [\"Denver, CO\"]}} or {\"profile\": {\"phone\": \"+1 555 0100\"}}. Field names are as freeapply_get_settings returns them."
    • Changedfreeapply_workflow2 fields changed
      • addedInput schema / properties / name / description
        Added value: +"Procedure to get. Optional; omit to list the procedures."
      • addedInput schema / properties / name / enum
        Added value: +[
        +  "freeapply-setup",
        +  "freeapply-apply",
        +  "freeapply-replies"
        +]
  6. 25 tool updatesv0.1.0
    • First observedfreeapply_add_job
    • First observedfreeapply_autorun
    • First observedfreeapply_check_duplicate
    • First observedfreeapply_check_text
    • First observedfreeapply_fetch_posting
    • First observedfreeapply_finish_reply_check
    • First observedfreeapply_get_answers
    • First observedfreeapply_get_settings
    • First observedfreeapply_get_stats
    • First observedfreeapply_list_jobs
    • First observedfreeapply_open_dashboard
    • First observedfreeapply_preview_shared_data
    • First observedfreeapply_record_reply
    • First observedfreeapply_reply_check_plan
    • First observedfreeapply_save_resume_profile
    • First observedfreeapply_save_resume_text
    • First observedfreeapply_set_outcome
    • First observedfreeapply_site_account
    • First observedfreeapply_site_status
    • First observedfreeapply_status
    • First observedfreeapply_sync_shared_data
    • First observedfreeapply_throttle
    • First observedfreeapply_update_job
    • First observedfreeapply_update_settings
    • First observedfreeapply_workflow

TDQS

A4.5/5.0

Scored across 18 tools

Disambiguation4/5

Each tool targets a distinct slice of the workflow (claim, update, list, stats, settings, replies, autorun, sharing), and descriptions carry explicit 'not for X, use Y' routing that preempts most confusion. The job lifecycle is deliberately split across claim_job/update_job/record_outcome/clear_to_submit, which an agent must learn, and several tools bundle multi-action parameters (get/save, start/read/mark/finish, preview/sync) that add internal selection burden.

Naming Consistency4/5

All 18 names are uniformly snake_case with a consistent freeapply_ prefix, so the set is easy to scan and group. A few verbs are weaker than others (manage_autorun, manage_answers are generic; clear_to_submit is not a clean verb_noun phrase), but no convention mixing.

Tool Count4/5

18 tools is slightly above the comfortable band, but the domain is genuinely broad (job lifecycle, settings, autorun sessions, email replies, site accounts, data sharing). Each tool maps to a real distinct operation, though a couple of the multi-action tools could be consolidated.

Completeness4/5

Coverage is strong: claim, update, list, stats, settings read/write, posting fetch, text verification, saved answers, submit clearance, site-signin handling, reply checking, outcome recording, and sharing are all present. Remaining gaps (deleting/untracking a job, résumé management, job search) are explicit and deliberately delegated to the dashboard or the browser, so agents can work around them.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables users to search for jobs, prefill applications using AI, and automate submissions across major platforms like Lever and Ashby directly from Claude or Cursor. It provides a full suite of tools for managing job queues, profile data, and resumes within a chat interface.
    37
    MIT
  • F
    license
    Not graded
    quality
    D
    maintenance
    Enables Claude to parse CVs, search job boards (Remotive, Arbeitnow, Adzuna, Greenhouse/Lever), tailor resumes and cover letters, and prepare application packages with direct apply links—without ever auto-submitting. It runs 100% locally and free, storing jobs and applications as JSON files.
    -
  • F
    license
    A
    quality
    C
    maintenance
    Enables an LLM client to read a structured CV resource and send tailored application emails to recruiters via SMTP.
    1
    -
  • F
    license
    Not graded
    quality
    B
    maintenance
    Enables automated job searching from multiple boards, filtering matches against saved criteria, deduplicating seen postings, and tracking application statuses. Runs locally and integrates with Claude Desktop for natural-language queries and updates.
    -