MCP-native job search: deterministic sourcing + scoring, with Claude (the host model) as the job-fit evaluator. Inline review UI as an MCP App.
Job Search MCP demonstrates solid definition quality with well-structured tool schemas, clear descriptions, and thoughtful parameter design. All 6 tools have explicit descriptions (194 - 450 chars, within baseline 34 - 392 range). Input schemas are complete with typed parameters and descriptions. Tool names follow verb_noun convention (find_jobs, evaluate_jobs, set_status). Key strengths: parameter constraints (enums for 'status', 'view'), defensive output projection (slimJob), and composition (tools chain logically). Weaknesses: no tool annotations (readOnlyHint/destructiveHint), limited error guidance in descriptions, and no explicit output schema documentation in tool registration. Per-tool scores range 68 - 78, averaging 72.
Score a batch of jobs (0-100 fit score + reason each) and persist them. The model reads the candidate profile + job descriptions and returns a holistic fit score per job. Scores are clamped to 0-100 and persisted in the store; the server does NOT call an external LLM. After scoring, call show_board to render the single ranked board.
Source live jobs (LinkedIn + Greenhouse, Lever, Ashby, Workday, SmartRecruiters, Hacker News, RemoteOK, Remotive), dedup them, and return them as text with full descriptions. Uses the saved profile's roles/location by default; pass query/location/filters to override. This returns UNSCORED jobs and does NOT show a card UI — immediately score all of them with evaluate_jobs (a 0-100 fit score + reason each), then show_board once, to present the single ranked board. Do not just list them back.
Retrieve the saved candidate profile (name, skills, target roles, location, remote preference, years of experience). Returns null if no profile has been saved yet.
Save or update the candidate profile (name, skills, target roles, location, remote preference, years of experience). The profile is used by find_jobs as defaults and by evaluate_jobs as context for scoring.
Triage a job: mark it as 'saved' (tracking), 'applied' (applied), or 'dismissed' (rejected). Persists the status in the store and returns the updated board.
No tool annotations (readOnlyHint, destructiveHint, idempotentHint) declared in tool registration. Agents cannot infer which tools are safe to retry or have side effects.
Error handling descriptions lack recovery guidance. E.g., evaluate_jobs does not document what happens if job_id is invalid or if score is out of range (0 - 100 clamping is mentioned in code but not in tool description).
Output schema not explicitly documented in tool descriptions. Agents must infer the structure of returned job objects from code. find_jobs description does not state it returns {jobs: [...], count, scored, profile, view}.
Inferred effective spec: 2025-06-18+.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | C | 61 | 2025-06-18+ | v2 |
Render the ranked job board (or saved/applied tracker). Returns all jobs in the requested view, ranked by match score (highest first). The review UI reads this and renders interactive cards.
find_jobs description mentions 'UNSCORED jobs' and instructs to call evaluate_jobs, but does not document the matchScore field default (-1) or explain the workflow clearly enough for agents unfamiliar with the domain.
set_status parameter 'status' uses enum constraint in code (registerAppTool) but enum values not visible in provided source snippet. If enum is missing from schema, agents may pass invalid values.