Local-first MCP server for tracking job applications, companies, and vacancies in SQLite
21 tools with consistent verb-noun naming (add_, get_, list_, update_, delete_). All tools have descriptions (avg 120 chars, within baseline 34-392). Input schemas present for all tools with typed parameters and enums (status, track, relevance, etc.). However, parameter descriptions are generic ('optional' repeated 200+ times); output schemas undocumented; error handling minimal (no recovery guidance); no tool annotations (readOnlyHint/destructiveHint). Composition is sound, tools chain well (e.g., list_applications → get_application → add_note). Security: no secrets in params. Missing: pagination guidance in list tools, output schema documentation, actionable error messages.
Create a job application record. Use after tailoring a resume for a JD. Pass vacancy_id (or company_id) to file it under an existing company/vacancy; a bare company name auto-creates the company record.
Add an employer to the company database. Fails if the name already exists.
Add a note, call, or email event to an application timeline.
Add a job vacancy to a company.
Attach a file to an application. Copies the file into the tracker's data dir; kind=resume also sets it as the application's resume_path.
Get aggregate statistics about companies in the database.
Delete a company and all its associated vacancies and applications.
Output schemas undocumented. Tools return Row objects with no schema definition visible in source. LLMs cannot infer what fields to expect (e.g., does get_application return events/attachments inline or separately?). Breaks downstream tool chaining and forces agents to guess field names.
Parameter descriptions are generic ('optional') and lack actionable constraints. E.g., 'resume_variant' enum is documented, but 'salary_range', 'location_policy', 'notes' have no format guidance. LLMs cannot validate input before calling.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | C | 68 | 2026-07-28+ | v2 |
Delete a vacancy and all its associated applications.
Application funnel stats and breakdown by resume variant.
Get full application detail including events and attachments.
Get one company with its full tree: vacancies, and the applications filed under each vacancy.
Get one vacancy with its company and all applications filed under it.
List job applications, optionally filtered by status, source, search text, company or vacancy.
List employers from the company database. Filter by search text, status, relevance (high = remote/US/global), sphere, priority, or remote/US only.
Follow-ups: overdue, stale applied (5+ days no answer), upcoming week.
Get list of all unique business spheres in the company database.
List job vacancies, optionally filtered by company, status, track, search text, or priority.
Update editable fields on a job application. Only provided fields are changed.
Update company fields. Only provided fields are changed.
Update the status of a job application.
Update vacancy fields. Only provided fields are changed.
No pagination guidance in list tools. list_applications, list_companies, list_vacancies accept no limit/offset/cursor parameters. Large result sets will blow context windows. Baseline pattern requires pagination for discovery tools.
No tool annotations (readOnlyHint, destructiveHint, idempotentHint). Destructive tools (delete_company, delete_vacancy) lack explicit marking. LLMs cannot distinguish safe reads from irreversible writes without reading descriptions.
Error handling minimal. No recovery guidance in tool descriptions. E.g., 'Application not found' (404) does not suggest 'try list_applications() to find valid IDs'. Agents cannot self-correct on failures.