Production-ready MCP server for Greenhouse, designed for recruiters and hiring teams
Strong foundation with 22 well-named tools, comprehensive descriptions, and clear parameter documentation. All tools have descriptions (10 - 200 chars, well within baseline). Input schemas are present and typed. However, output schemas are not documented in the source code provided, and error handling guidance is minimal. Tool descriptions include helpful dependency hints (e.g., 'search_candidates_by_name → get_candidate'), which aids composition. No tool annotations (readOnlyHint, destructiveHint, idempotentHint) detected. Risk classifications are inferred from tool names and descriptions, not explicit metadata.
Move a candidate forward one stage in their job pipeline. Write operation. Users say "advance Sarah to the next stage" or "move John forward." To get the application_id: search_candidates_by_name → get_candidate → match the application to the job. Stage IDs are optional — omit to advance to the natural next stage. To skip stages, use move_application_same_job. For bulk advancing, use bulk_advance.
Apply an existing candidate to a job. Write operation. Users say "add Sarah to the Backend Engineer role." Resolve both IDs first: candidate — search_candidates_by_name; job — list_jobs → match by name. The candidate must already exist (create_candidate first if needed). For sourced prospects, use add_prospect. For partner submissions, use post_candidate.
Create or replace an approval flow for a job. Write operation — overwrites existing. To find job_id: list_jobs → match by name. For approver user IDs: list_users → match by name.
Permanently delete an application. Destructive — cannot be undone. To find the application_id: search_candidates_by_name → get_candidate → match the application to the job. Consider reject_application instead — it preserves history and can be reversed with unreject_application.
Output schemas not documented. Tool descriptions explain what is returned in prose (e.g., 'Returns notes, emails, stage changes'), but formal output schema definitions are not visible in the source code. LLMs cannot reliably extract fields from unstructured responses.
No tool annotations (readOnlyHint, destructiveHint, idempotentHint) detected. Risk classifications are inferred from tool names and descriptions, not explicit metadata. Agents cannot reliably determine which tools are safe to retry or which modify state.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | B | 72 | 2026-07-28+ | v2 |
Download content from a Greenhouse attachment URL. Read-only. Use when you have a specific attachment URL from a candidate or application record (e.g., from get_candidate's attachments array).
Get a candidate's activity timeline. Read-only. Users say "show me Sarah's history" or "what's happened with this candidate?" To find candidate_id: search_candidates_by_name. Returns notes, emails, stage changes, and other timeline events in chronological order.
Get a single application by ID. Read-only. Users rarely know application IDs. To find one: search_candidates_by_name → get_candidate → the applications array has each application's ID and job name. For a complete screening package with resume and location, use screen_candidate.
Get a specific approval flow for a job. Read-only. Returns flow type, approver groups, and current status. To find job_id: list_jobs → match by name. For approval_flow_id: list_approvals_for_job.
List applications with optional filters. Read-only. Users say "show me applications for [job name]" or "what came in this week." To filter by job: list_jobs → find by name → use its job_id. To filter by candidate: search_candidates_by_name → candidate_id. For pipeline views grouped by stage, use pipeline_summary. For stale candidates, use stale_applications or candidates_needing_action.
List approval flows for a job. Read-only. To find job_id: list_jobs → match by name.
List all pending approvals for a user (or org-wide). Read-only. To find user_id: list_users → match by name or email. Omit user_id to see all pending approvals across the organization.
Transfer a candidate to a completely different job. Write operation. Users say "move Sarah from Backend to Frontend Engineer." You need the application_id (search_candidates_by_name → get_candidate → match app) and the new_job_id (list_jobs → match by name). Optionally set a starting stage with new_stage_id (list_job_stages_for_job on the target job). To move within the SAME job, use move_application_same_job instead.
Skip a candidate to a specific stage within the same job. Write operation. Users say "move Sarah straight to the onsite stage" or "skip phone screen." To get the application_id: search_candidates_by_name → get_candidate → match app to job. For stage IDs: list_job_stages_for_job → find by name. To advance to just the next stage, use advance_application instead.
Conversion rates and stage metrics for a job. Read-only. Users say "what are our conversion rates for the Backend role?" or "where are we losing candidates?" To find job_id: list_jobs → match by name. Returns per-stage counts, conversion percentages, and time-in-stage metrics.
Download and return a candidate's most recent resume text. Read-only. Users say "pull up Sarah's resume" or "show me John's CV." To find candidate_id: search_candidates_by_name. Returns extracted text from the most recent resume attachment. For batch reading, use batch_read_resumes.
Replace one approver with another in an approval flow. Write operation. Users say "swap John for Sarah on the Backend approval." For user IDs: list_users → match by name. For job_id: list_jobs. For approval_flow_id: list_approvals_for_job.
Trigger an approval request for a flow on a job. Write operation. To find job_id: list_jobs → match by name. For approval_flow_id: list_approvals_for_job.
Which candidate sources produce the best results. Read-only. Users say "which sources are working?" or "where should we spend recruiting budget?" Pass job_id (list_jobs → match by name) for one role, or omit for org-wide analysis. Returns volume, active rate, and hire rate per source.
Submit an application through the public job board. Write operation. For internal application creation (as a recruiter/admin), use create_application instead. This endpoint mirrors what external candidates do when they apply through the public board.
Time-to-hire metrics for hired candidates. Read-only. Users say "how long does it take to hire?" or "what's our average days-to-offer?" Pass job_id (list_jobs → match by name) for one role, or omit for org-wide metrics. Returns average, median, min, max days.
Update an application's source, referrer, or custom fields. Write operation. To find the application_id: search_candidates_by_name → get_candidate → match the application to the job. Only updates fields you provide. For source_id: list_sources. For custom field IDs: list_custom_fields.
Generate webhook configuration instructions for Greenhouse. Read-only. Produces the exact values to enter in Greenhouse UI (Configure > Dev Center > Webhooks) and stores the generated secret key in the local database.
Error handling guidance missing. Tool descriptions do not explain what errors can occur, how to recover, or what the LLM should do next. E.g., 'candidate must already exist' is mentioned for create_application, but no error response format or recovery path is documented.
Pagination parameters present but inconsistent. list_applications accepts 'paginate' (string: 'single'|'all'), but other list tools (list_approvals_for_job, list_pending_approvals) lack pagination parameters. Agents cannot reliably fetch large result sets.
Parameter 'referrer' in create_application and update_application is typed as 'object' with no schema. Description says '{type:"id", value:user_id} or {type:"outside",...}' but the exact structure is not formally defined. LLMs may construct invalid payloads.