Greenhouse MCP
Server Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
| GREENHOUSE_API_KEY | No | Harvest API key | |
| GREENHOUSE_LOG_FILE | No | Log file path (defaults to stderr) | |
| GREENHOUSE_LOG_LEVEL | No | Log level: 'debug', 'info', 'warning' (default), 'error' | warning |
| GREENHOUSE_BOARD_TOKEN | No | Job board URL slug | |
| GREENHOUSE_ON_BEHALF_OF | No | Greenhouse user ID for write audit trail | |
| GREENHOUSE_TOOL_PROFILE | No | Tool profile: 'full' (default), 'recruiter', or 'read-only' | full |
Instructions
Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.
This server publishes no instructions, or was last inspected before Glama recorded them.
Capabilities
Features and capabilities supported by this server
Protocol revision2025-11-25
| Capability | Details |
|---|---|
| tools | {
"listChanged": false
} |
| prompts | {
"listChanged": false
} |
| resources | {
"subscribe": false,
"listChanged": false
} |
| experimental | {} |
Tools
Functions exposed to the LLM to take actions
| Name | Description |
|---|---|
| add_attachmentA | Attach a file (resume, cover letter, etc.) to a candidate. Write operation. Harvest v3 stores every attachment on an application, so this attaches to application_id if given, otherwise to the candidate's most recently active application (the response's application_id shows which). To get candidate_id: search_candidates_by_name. To choose the application, see get_candidate's applications array, or use add_attachment_to_application. |
| add_educationA | Add an education entry to a candidate. Write operation. To find candidate_id: search_candidates_by_name. For school_id: list_schools; degree_id: list_degrees; discipline_id: list_disciplines (match by name — these are custom field option IDs in Harvest v3). |
| add_email_note_to_candidateA | Log an email on a candidate's activity feed. Write operation. Records an email exchange (to, from, cc, subject, body) as an activity entry. This logs the email — it does not send one. To get candidate_id: search_candidates_by_name. |
| add_employmentA | Add an employment entry to a candidate. Write operation. company_name, title and start_date are required by Greenhouse. To find candidate_id: search_candidates_by_name. |
| add_note_to_candidateA | Add a text note to a candidate's Notes tab / activity feed. Write operation. Users say "add a note to Sarah's profile" or "log that I spoke with John." The note is authored by the configured Greenhouse user. To get candidate_id: search_candidates_by_name. |
| add_prospectA | Create a sourced prospect in a prospect pool. Write operation. Users say "add this person as a prospect for the Engineering pool." Unlike create_candidate with a job_id, this creates a prospect not yet in an active job pipeline. For pool/stage IDs: list_prospect_pools → match by name. To later convert to an active candidate, use convert_prospect. |
| anonymize_candidateA | Anonymize a candidate's personal data for GDPR/privacy compliance. Write operation. Scrubs the listed data groups (name, emails, phones, attachments, notes, etc.) while preserving the record and hiring activity for reporting. Irreversible; large scopes complete asynchronously. Greenhouse requires an explicit list of fields — confirm with the user what to remove. To get the candidate_id: search_candidates_by_name → get_candidate. |
| create_candidateA | Create a new candidate record, optionally applying them to a job. Write operation. Users say "add a new candidate — Jane Doe at Acme Corp for the Backend role." Check for duplicates first with search_candidates_by_name or search_candidates_by_email. Pass job_id (list_jobs) to create the application in the same call; the response then has both candidate and application. Without job_id, use create_application afterwards. For sourced prospects, use add_prospect instead. |
| delete_candidateA | Permanently delete a candidate and all their applications. Destructive — cannot be undone. To get the candidate_id: search_candidates_by_name → get_candidate. For GDPR compliance, consider anonymize_candidate instead — it preserves the record while removing personal data. |
| get_candidateA | Get a candidate's full profile by ID. Read-only. Returns name, contact info, tags, custom fields, plus (fetched alongside, since v3 no longer embeds them) applications (each with id, job_id, job_name, stage_name, job_interview_stage_id, status), attachments (with time-limited download URLs), educations (with school/degree/discipline names) and employments. This is the central lookup — most workflows route through here after resolving a name via search_candidates_by_name. For a screening package with resume and location, use screen_candidate. |
| list_candidatesA | List candidates with optional filters. Read-only. For finding a specific person, use search_candidates_by_name (by name) or search_candidates_by_email (by email) — faster and simpler. Use this tool for bulk operations: date-range queries, fetching by specific IDs, or paginating through the full database. Created and updated date filters can't be combined in one call. Candidates here are profile-only (no applications or attachments) — use get_candidate or list_applications(candidate_id=...) for those. |
| merge_candidatesA | Merge a duplicate candidate into a primary record. Write operation — cannot be undone. Users say "these two Sarah Chens are the same person." Find both records with search_candidates_by_name. The duplicate's applications, attachments, notes and tags move to the primary, and the duplicate record is deleted. Returns the merged primary candidate. |
| remove_educationA | Remove an education entry from a candidate. Write operation. To find candidate_id: search_candidates_by_name. For education_id: get_candidate → check the educations array. Checks the record belongs to this candidate before deleting it. |
| remove_employmentA | Remove an employment entry from a candidate. Write operation. To find candidate_id: search_candidates_by_name. For employment_id: get_candidate → check the employments array. Checks the record belongs to this candidate before deleting it. |
| update_candidateA | Update a candidate's profile. Write operation — only changes fields you provide. Users say "update Sarah's title to Senior Engineer." To get the candidate_id: search_candidates_by_name → get_candidate. For custom field IDs: list_custom_fields → match by name. To add or remove a single tag without replacing the list, use add_tag_to_candidate / remove_tag_from_candidate. |
| add_attachment_to_applicationA | Attach a file to a specific application. Write operation. To find the application_id: search_candidates_by_name → get_candidate → match the application to the job. The file type is inferred from the filename extension. add_attachment does the same when you only know the candidate. |
| advance_applicationA | 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. from_stage_id must be the application's current job_interview_stage_id (Greenhouse rejects stale moves); omit it and it is looked up for you. Omit to_stage_id to advance to the natural next stage. To skip stages, use move_application_same_job. For bulk advancing, use bulk_advance. |
| convert_prospectA | Convert a sourced prospect into an active candidate on a job. Write operation. Users say "move this prospect into the Backend pipeline." The prospect's application_id comes from their prospect record (get_candidate → applications array, where prospect is true). Target job_id from list_jobs → match by name. |
| create_applicationA | 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 can also create the candidate and application in one step). Attachments are uploaded to the new application afterwards; their results are under attachment_results. For sourced prospects, use add_prospect. For partner submissions, use post_candidate. |
| delete_applicationA | 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. |
| get_applicationA | Get a single application by ID. Read-only. Returns the application with job_name, its current stage (stage_name and job_interview_stage_id — the from_stage_id for moves), status, source_id, rejection_reason_id, custom fields, and its attachments (resume etc., with time-limited download URLs). 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. |
| hire_applicationA | Mark a candidate as hired. Write operation — finalizes the hiring decision. Users say "hire Sarah for the Backend role." To get the application_id: search_candidates_by_name → get_candidate → match the application to the job. Optionally fills a job opening (opening_id from list_job_openings) and records a close reason (close_reason_id from list_close_reasons). |
| list_applicationsA | 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. Each application has job_id + job_name, the current stage (stage_name, and job_interview_stage_id for moves), status ('in_process', 'rejected', 'hired', 'converted'), source_id, recruiter_id/coordinator_id, rejection_reason_id and created_at (the applied date). For pipeline views grouped by stage, use pipeline_summary. For stale candidates, use stale_applications or candidates_needing_action. |
| move_applicationA | 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). The current stage is looked up automatically unless from_stage_id is given. To move within the SAME job, use move_application_same_job instead. |
| move_application_same_jobA | 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. The current stage is looked up automatically unless from_stage_id is given. To advance to just the next stage, use advance_application instead. |
| reject_applicationA | Reject a candidate from a job. Write operation. Users say "reject Sarah from the Backend role." To get the application_id: search_candidates_by_name → get_candidate → match the application to the job. A rejection_reason_id is required: list_rejection_reasons → match by name. For email templates: list_email_templates; the email is sent from email_from_user_id, defaulting to the configured Greenhouse user. Can be reversed with unreject_application. For bulk rejections, use bulk_reject. |
| unreject_applicationA | Reverse a rejection, returning the candidate to active status. Write operation. Users say "undo the rejection for Sarah" or "bring Sarah back." To get the application_id: search_candidates_by_name → get_candidate → find the rejected application in their applications array. |
| update_applicationA | Update an application's source, referrer, recruiter, coordinator 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. To change a rejection reason, use update_rejection_reason. |
| update_rejection_reasonA | Change the rejection reason on an already-rejected application. Write operation. To find the application_id: search_candidates_by_name → get_candidate → find the rejected application. For the new reason: list_rejection_reasons → match by name. Looks up the application's rejection details record and updates its reason. |
| create_jobA | Create a new job from a template. Write operation — admin only. Users say "create a new Backend Engineer role." Requires template_job_id — use list_jobs to find a similar existing job. For department_id: list_departments → match by name. For office_ids: list_offices → match. After creation, use update_job_post to set the public listing content. |
| get_jobA | Get full details for a job by ID. Read-only. Returns name, status, requisition_id, notes, custom fields, department and offices ({id, name}), openings, and the hiring team (hiring_managers, recruiters, coordinators, sourcers as {id, name, email}). Use list_jobs to find the job_id by name first. For the public listing, use list_job_posts_for_job. For pipeline stages, use list_job_stages_for_job. |
| list_jobsA | List all jobs with optional filters. Read-only. This is the primary tool for resolving job titles to job IDs. When a user mentions a job by name ("Backend Engineer"), use this to find the matching job_id. Filter by status ('open'/'closed'/'draft'), department_id (list_departments), or office_id (list_offices). Each job includes department and offices as {id, name}. Openings are not embedded — use list_job_openings; the hiring team is on get_job. For pipeline views, use pipeline_summary with the job_id. |
| update_jobA | Update a job's name, department, offices, notes, or custom fields. Write operation. To find job_id: list_jobs → match by name. Only updates fields you provide. For department_id: list_departments. For office_ids: list_offices. To modify the public listing, use update_job_post instead. A job's open/closed status can't be set directly in Harvest v3: close its openings with update_job_opening(status='closed') (list_job_openings to find them). |
| add_job_post_locationA | Add a location to a job post. Write operation — admin only. v3 job posts can have several locations. The post's job board must allow the location type. To find job_post_id: list_job_posts_for_job. |
| get_job_postA | Get a job post by ID. Read-only. Returns title, content (HTML), live status, job_id, job_board_id, public_url, application questions, and locations. To find post IDs: list_job_posts_for_job. |
| get_job_post_custom_locationsA | Get the custom-list locations selected on a job post. Read-only. Custom locations are per-job-board dropdown values. Returns {"items": [{id, value, active, greenhouse_job_board_id, job_post_location_id}]}. For all of a post's locations (free text, office, custom), use get_job_post. To find job_post_id: list_job_posts_for_job. |
| get_job_post_for_jobA | Get a specific job post scoped to a job. Read-only. Same as get_job_post, but returns 404 if the post doesn't belong to the job. To find job_id: list_jobs → match by name. To find post_id: list_job_posts_for_job. |
| list_job_postsA | List all job posts (public listings) across all jobs. Read-only. A job post is the public-facing listing for a job. Each post includes its application form questions and a locations array (a post can have several locations in v3). For posts on a specific job, use list_job_posts_for_job (job_id from list_jobs → match by name). |
| list_job_posts_for_jobA | List job posts for a specific job. Read-only. To find job_id: list_jobs → match by name. Returns the public listing(s) including title, content, live status, public_url, application questions, and locations. |
| remove_job_post_locationA | Remove a location from a job post. Write operation. To find job_post_location_id: get_job_post → locations[].id. |
| update_job_postA | Update a job post's title, location, or content. Write operation — admin only. To find job_post_id: list_job_posts_for_job (job_id from list_jobs → match by name). In v3 locations are separate records: passing location adds it as a free-text location and then removes the post's previous locations. For multiple or office-based locations, use add_job_post_location / remove_job_post_location. |
| update_job_post_statusA | Publish or unpublish a job post. Write operation. Controls visibility on job boards ('offline' sets the post back to draft). To find job_post_id: list_job_posts_for_job (job_id from list_jobs → match by name). |
| get_job_stageA | Get a single stage by ID. Read-only. Returns stage name, sort_order, job_id, and its configured interviews. Usually list_job_stages_for_job is more useful — it gives all stages in pipeline order. |
| list_job_stagesA | List all job stages across all jobs. Read-only. Returns stage id, job_id, name, sort_order, and active. For stages on a specific job in pipeline order (with their interviews), use list_job_stages_for_job instead — it's more useful for resolving stage names to IDs. |
| list_job_stages_for_jobA | List pipeline stages for a specific job in order. Read-only. This is the primary tool for resolving stage names to stage IDs. When a user says "move to the onsite stage," use this to find the stage_id (the job_interview_stage_id used by move/advance). Stages are sorted by sort_order, and each has an interviews array (the stage's configured interviews — their id is the interview_id that create_interview expects; scheduling_type 'needs_scheduling' means it is a calendared interview). To find the job_id first: list_jobs → match by name. |
| bulk_create_job_openingsA | Create many openings in one asynchronous request. Write operation — admin only. Returns bulk_action_uuid and status; check progress with get_bulk_request_status. For one opening use create_job_opening. |
| bulk_delete_job_openingsA | Delete many openings in one asynchronous request. Destructive — cannot be undone. Returns bulk_action_uuid; check progress with get_bulk_request_status. |
| bulk_update_job_openingsA | Update or close many openings in one asynchronous request. Write operation. Use to close all of a job's openings at once (list_job_openings → ids). Returns bulk_action_uuid; check progress with get_bulk_request_status. |
| create_job_openingA | Add a new headcount to a job. Write operation. Users say "add another opening to the Backend role." To find job_id: list_jobs → match by name. Openings are created open; with status='closed' the new opening is closed straight after (with close_reason_id if given). |
| delete_job_openingA | Delete a job opening. Destructive — cannot be undone. To find job_id: list_jobs → match by name. To find opening_id: list_job_openings on the job. |
| get_bulk_request_statusA | Check the progress of any v3 bulk request. Read-only. Use after a bulk tool returns a bulk_action_uuid (bulk job openings, custom field options in batches over 50). Returns status (building/pending/in_progress/completed/failed), record_count, success_count, failure_count, and short-lived result URLs. |
| get_job_openingA | Get a specific opening on a job. Read-only. Returns open/status, close_reason_id, custom fields, and the hired application_id if filled. To find job_id: list_jobs → match by name. To find opening_id: list_job_openings on the job. |
| list_job_openingsA | List openings (headcount) for a job. Read-only. An opening represents one position to fill — a job can have multiple. Each opening has id, opening_id (external ID), open (bool) and status ('open'/'closed'), close_reason_id, application_id (the hire, if filled), target_start_on, and custom_fields. To find job_id: list_jobs → match by name. |
| update_job_openingA | Update a job opening's status, target start date, or custom fields. Write operation. To find job_id: list_jobs → match by name. To find opening_id: list_job_openings on the job. For close_reason_id: list_close_reasons → match by name. Closing a job's last open opening closes the job. |
| get_current_offerA | Get the current (latest version) offer for an application. Read-only. Returns 404 if the application has no offer. To find application_id: search_candidates_by_name → list_applications(candidate_id=...) → match the application to the job. |
| get_offerA | Get a single offer by ID. Read-only. Returns offer status, version, starts_on, sent_on, resolved_at, opening_id, and custom fields. |
| list_offersA | List offers across all applications. Read-only. Each offer has id, version, application_id, candidate_id, job_id, opening_id, status, starts_on, sent_on, resolved_at, and custom_fields. Every revision is returned (older ones have status 'Deprecated'); set current_only=true for just each application's current offer. For a specific candidate's offers, use list_offers_for_application (search_candidates_by_name → list_applications(candidate_id=...) → match the application → use its ID). |
| list_offers_for_applicationA | List all offers (every version) made on a specific application. Read-only. Sorted newest version first. To find application_id: search_candidates_by_name → list_applications(candidate_id=...) → match the application to the job. For the current offer only, use get_current_offer. |
| update_current_offerA | Update the current offer on an application. Write operation. Looks up the application's latest offer version and patches it (start date → starts_on). To find application_id: search_candidates_by_name → list_applications(candidate_id=...) → match the application to the job. For custom field IDs: list_custom_fields. |
| get_scorecardA | Get a single scorecard by ID. Read-only. Returns the interviewer, interview, attribute ratings, question answers, notes, and overall recommendation (candidate_rating). To find scorecard IDs: list_scorecards_for_application. |
| list_scorecardsA | List interview scorecards across all applications. Read-only. Each scorecard has application_id, candidate_rating (also as overall_recommendation), notes, status, interviewed_at, submitted_at and, with include_details, interviewer/submitted_by {id, name, email}, interview name, attributes [{name, rating, note}], ratings grouped by rating, and questions [{question, answer}]. v3 scorecards carry no candidate_id — use application_id. For a specific candidate, use list_scorecards_for_application (search_candidates_by_name → list_applications(candidate_id=...) → match application → use its ID). |
| list_scorecards_for_applicationA | List scorecards submitted for a specific application. Read-only. To find application_id: search_candidates_by_name → list_applications(candidate_id=...) → match the application to the job. Returns each interviewer's attribute ratings, question answers, notes and overall recommendation (candidate_rating). |
| create_interviewA | Record a scheduled interview for an application. Write operation. Users say "schedule an interview for Sarah on the Backend role." To get application_id: search_candidates_by_name → list_applications(candidate_id=...) → match app. For interviewer_ids: list_users → match by name. interview_id is the job interview from list_job_stages_for_job (interviews[].id). This records the interview in Greenhouse; it does not send calendar invites. |
| delete_interviewA | Cancel a scheduled interview. Write operation — cannot be undone. To find interview_id: list_interviews_for_application on the candidate's app. |
| get_interviewA | Get a scheduled interview by ID. Read-only. Returns details: application, interview name, interviewers, organizer, times, location, and status. To find interview IDs: list_interviews_for_application on the candidate's app. |
| list_interviewsA | List scheduled interviews across all applications. Read-only. Each interview has id, application_id, job_id, starts_at/ends_at (or all_day_start_on/all_day_end_on), status, location, video_conferencing_url, plus (with include_details) interview {id, name}, interviewers [{id, name, email, response_status, scorecard_id}] and organizer. For a specific candidate's interviews, use list_interviews_for_application (search_candidates_by_name → list_applications(candidate_id=...) → match the application → use its ID). |
| list_interviews_for_applicationA | List scheduled interviews for a specific application. Read-only. To find the application_id: search_candidates_by_name → list_applications(candidate_id=...) → match the application to the job. Returns all interviews with times, interview name, interviewers (with their scorecard_id), and status. |
| update_interviewA | Update a scheduled interview's time, interviewers, or location. Write operation. To find interview_id: list_interviews_for_application on the candidate's app. For new interviewer_ids: list_users → match by name. When replacing interviewers, existing panel members keep their RSVP; new ones start as needs_action. |
| add_email_to_userA | Add a secondary email address to a Greenhouse user. Write operation. To find user_id: list_users → match by name or email. The address stays unverified until the user confirms it. |
| change_user_permission_levelA | Demote a user to Basic, revoking all their permissions. Write operation — admin only. Removes the user's Site Admin status and every job-level permission (Greenhouse "revoke permissions"). Promoting a user is not possible via the API — grant job roles with add_job_permission instead. To find user_id: list_users → match by name or email. |
| create_userA | Create a new Greenhouse user account. Write operation — admin only. After creating, use add_job_permission to grant access to specific jobs, or add_future_job_permission for automatic access to new jobs. |
| disable_userA | Deactivate (disable) a Greenhouse user, preventing login. Write operation. Users say "deactivate John's account." To find user_id: list_users → match by name or email. Can be reversed with enable_user. Returns {"success": true} on success. |
| enable_userA | Re-activate (enable) a previously deactivated user. Write operation. To find user_id: list_users → match by name or email. Returns {"success": true} on success. |
| get_userA | Get a Greenhouse user's profile by ID. Read-only. Returns name, primary_email, |
| list_usersA | List all Greenhouse users (team members, not candidates). Read-only. This is the primary tool for resolving team member names to user IDs.
When another tool needs a user_id (interviewer, approver, hiring manager),
use this to find the person by name or email. Filter by email for exact
lookup (matches the primary email first, then any secondary address), or
paginate to scan. Each user has |
| update_userA | Update a user's name, title, primary email, offices or departments. Write operation. To find user_id: list_users → match by name or email. To make a new address primary, first add it with add_email_to_user and have it verified. |
| add_future_job_permissionA | Auto-grant a role on all future jobs. Write operation — admin only. Users say "give Sarah recruiter access to all new Engineering jobs." For user_id: list_users. For user_role_id: list_user_roles. Scope with office_id (list_offices) or department_id (list_departments). |
| add_job_permissionA | Grant a user a role on a specific job. Write operation — admin only. Users say "give Sarah recruiter access to the Backend role." For user_id: list_users → match by name. For job_id: list_jobs → match by name. For user_role_id: list_user_roles → match by role name (role_type 'job_admin'). |
| list_future_job_permissionsA | List auto-apply permission rules for a user. Read-only. These rules automatically grant the user a role on new jobs matching
criteria (office_id, department_id; null = any). Rows carry |
| list_job_permissionsA | List all job-level permissions for a user. Read-only. To find user_id: list_users → match by name or email. Each row has its
own |
| remove_future_job_permissionA | Revoke a future job permission rule. Write operation — admin only. To find user_id: list_users → match by name. For the permission ID: list_future_job_permissions for the user. The permission ID alone identifies the rule; user_id is accepted for context. |
| remove_job_permissionA | Revoke a user's job-level permission. Write operation — admin only. To find user_id: list_users → match by name. For the permission ID: list_job_permissions for the user → match the job. The permission ID alone identifies the row; user_id is accepted for context. |
| create_departmentA | Create a new department. Write operation — admin only. For parent_id (optional): list_departments → find parent by name. |
| get_departmentA | Get a department by ID. Read-only. Returns name, parent_id, external_id, and |
| list_departmentsA | List all departments. Read-only. Resolves department names to IDs. When a user mentions a department
("Engineering"), use this to find its ID for list_jobs, create_job,
or add_future_job_permission. Each department has |
| update_departmentA | Update a department's name, parent or external ID. Write operation — admin only. To find department_id: list_departments → match by name. Greenhouse requires the name on every update, so the current name is kept when name is omitted. |
| create_officeA | Create a new office. Write operation — admin only. For parent_id (optional): list_offices → find parent by name. For the contact: list_users → match by name. |
| get_officeA | Get an office by ID. Read-only. Returns name, location, parent_id, and |
| list_officesA | List all offices. Read-only. Resolves office/location names to IDs. When a user mentions an office
or location, use this to find its ID for list_jobs, create_job, or
add_future_job_permission. Each office has a flat |
| update_officeA | Update an office's name, location, parent or contact. Write operation — admin only. To find office_id: list_offices → match by name. Greenhouse requires the name on every update, so the current name is kept when name is omitted. |
| create_custom_fieldB | Create a new custom field definition. Write operation — admin only. Defines a new field available on candidates, applications, jobs, offers, openings or users. |
| create_custom_field_optionsA | Add dropdown options to a custom field. Write operation — admin only. To find custom_field_id: list_custom_fields → match by name. Up to 50 options are created immediately and returned; larger lists are sent as an asynchronous Greenhouse bulk request. |
| delete_custom_fieldA | Delete a custom field and all its values. Destructive — cannot be undone. Admin only. To find custom_field_id: list_custom_fields → match by name. |
| delete_custom_field_optionsA | Delete dropdown options from a custom field. Destructive — cannot be undone. Admin only. To find custom_field_id: list_custom_fields → match by name. For option IDs: list_custom_field_options → match by name. Historical selections keep the (now inactive) option. Up to 50 options are deleted immediately; larger lists use an asynchronous bulk request. |
| get_custom_fieldA | Get a custom field definition by ID. Read-only. Returns field name, name_key, field type, value type, and configuration.
For single/multi-select fields, |
| list_custom_field_optionsA | List dropdown options for a custom field. Read-only. To find custom_field_id: list_custom_fields → match by name. Options
have |
| list_custom_fieldsA | List all custom field definitions. Read-only. Resolves custom field names to IDs. When a user mentions a custom field
by name, use this to find its ID (or |
| update_custom_fieldA | Update a custom field's name, privacy or description. Write operation — admin only. To find custom_field_id: list_custom_fields → match by name. Renaming does not change the field's name_key. |
| update_custom_field_optionsA | Update dropdown options on a custom field. Write operation — admin only. To find custom_field_id: list_custom_fields → match by name. For option IDs: list_custom_field_options → match by name. Up to 50 options are updated immediately; larger lists use an asynchronous bulk request. |
| list_sourcesA | List all candidate sources (job boards, referrals, agencies). Read-only. Resolves source names to IDs for create_application and update_application.
When a user mentions where a candidate came from, use this to find the
source_id. Each source has a |
| list_rejection_reasonsA | List all rejection reasons. Read-only. Resolves rejection reason names to IDs. When a user says "reject for
'not enough experience'," use this to find the ID, then pass it to
reject_application or bulk_reject. Each reason's |
| get_email_templateA | Get an email template by ID. Read-only. Returns template name, subject, body or html_body, email_type and sender settings. To find template_id: list_email_templates → match by name. |
| list_email_templatesA | List all email templates. Read-only. Resolves template names to IDs. When a user wants to send a rejection email, use this (email_type='candidate_rejection') to find the template ID for reject_application's rejection_email parameter. |
| add_tag_to_candidateA | Apply a tag to a candidate. Write operation. Users say "tag Sarah as 'referred'" or "mark John as strong hire." For candidate_id: search_candidates_by_name. For tag_id: list_tags → match by name. For bulk tagging, use bulk_tag instead. |
| create_tagA | Create a new candidate tag. Write operation. After creating, use add_tag_to_candidate to apply it. Note: bulk_tag creates tags on-the-fly, so pre-creation isn't needed for bulk ops. |
| delete_tagA | Delete a tag from the organization. Destructive — removes it from all candidates. To find tag_id: list_tags → match by name. |
| list_tagsA | List all candidate tags in the organization. Read-only. Resolves tag names to IDs. When a user says "tag Sarah as 'strong hire'," use this to find the tag_id, then add_tag_to_candidate. |
| list_tags_on_candidateA | List tags on a specific candidate. Read-only. To find candidate_id: search_candidates_by_name. Each item has the tag
|
| remove_tag_from_candidateA | Remove a tag from a candidate. Write operation. For candidate_id: search_candidates_by_name. For tag_id: list_tags_on_candidate → find the tag, or list_tags → match by name. |
| get_activity_feedA | 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 three lists,
newest first: |
| get_eeoc_for_applicationA | Get EEOC data for a specific application. Read-only. To find application_id: search_candidates_by_name → list_applications(candidate_id=...) → match the application to the job. |
| list_eeocA | List all EEOC data collected from applications. Read-only. Compliance data — self-reported race, gender, veteran, and disability status ({id, description} each). Used for federal reporting, not for hiring decisions. |
| get_answerA | Get a single demographic survey response by ID. Read-only. To find IDs: list_answers or list_answers_for_application. |
| get_answer_optionA | Get a demographic answer option by ID. Read-only. To find IDs: list_answer_options or list_answer_options_for_question. |
| get_questionA | Get a demographic question by ID. Read-only. To find IDs: list_questions or list_questions_for_question_set. |
| get_question_setA | Get a demographic question set by ID. Read-only. To find IDs: list_question_sets. |
| list_answer_optionsB | List all demographic answer options across all questions. Read-only. Each option has name, demographic_question_id, free_form, decline_to_answer, active and sort_order. |
| list_answer_options_for_questionA | List answer options for a specific demographic question. Read-only. To find question_id: list_questions or list_questions_for_question_set. |
| list_answersA | List all demographic survey responses submitted by candidates. Read-only. Each answer has application_id, demographic_question_id, demographic_answer_option_id and free_form_text. Resolve labels with list_questions and list_answer_options. |
| list_answers_for_applicationA | List demographic responses for a specific application. Read-only. To find application_id: search_candidates_by_name → list_applications(candidate_id=...) → match the application to the job. |
| list_question_setsA | List all demographic survey question sets. Read-only. Admin/compliance tool for managing demographic data collection. Each set has title, description, active and enabled. |
| list_questionsA | List all demographic survey questions across all sets. Read-only. Each question has name (the prompt), demographic_question_set_id, required, answer_type and sort_order. |
| list_questions_for_question_setA | List questions in a specific demographic question set. Read-only. To find question_set_id: list_question_sets. |
| create_or_replace_approval_flowA | Create or replace an approval flow for a job. Write operation — overwrites existing. If the job already has a flow of this approval_type, its approver groups are replaced; otherwise a new flow is created (pending — call request_approvals to start it). To find job_id: list_jobs → match by name. For approver user IDs: list_users → match by name. |
| get_approval_flowA | Get a specific approval flow for a job. Read-only. Returns flow type, approval_status, and approver groups with their approvers. To find job_id: list_jobs → match by name. For approval_flow_id: list_approvals_for_job. |
| list_approvals_for_jobA | List approval flows for a job. Read-only. To find job_id: list_jobs → match by name. Each flow has approval_type
(open_job, offer_job, offer_candidate), approval_status, sequential,
requested_by_id, and |
| list_pending_approvalsA | List all pending approvals for a user (or org-wide). Read-only. By default returns approvers whose decision is due now. Each item has approver_id, user_id, user_name, status, request_sent_at, job_id, offer_id, approval_type and approval_flow_id. To find user_id: list_users → match by name or email. Omit user_id to see all pending approvals across the organization. |
| replace_approverA | 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. The approver being removed must not have approved or rejected yet. |
| request_approvalsA | Trigger an approval request for a flow on a job. Write operation. Sends the approval request emails to the first approvers. To find job_id: list_jobs → match by name. For approval_flow_id: list_approvals_for_job. |
| add_hiring_team_membersA | Add members to a hiring team without replacing existing ones. Write operation. To find job_id: list_jobs → match by name. For member user_ids: list_users
→ match by name. Returns |
| get_hiring_teamA | Get the hiring team for a job. Read-only. Users say "who's on the hiring team for Backend Engineer?" To find job_id:
list_jobs → match by name. Returns members grouped by role:
hiring_managers, recruiters, coordinators and sourcers. Each member has
|
| remove_hiring_team_memberA | Remove someone from a job's hiring team. Write operation. Removes the user from every hiring-team role they hold on the job. To find job_id: list_jobs → match by name. For user_id: list_users → match by name, or get_hiring_team to see current members and their IDs. |
| replace_hiring_teamA | Replace the hiring team for a job. Write operation — overwrites existing members. Only the roles you pass are replaced; omitted roles are left alone.
Members missing from a passed list are removed and new ones are added.
To find job_id: list_jobs → match by name. For member user_ids:
list_users → match each person by name. Returns |
| get_prospect_poolA | Get a prospect pool and its stages by ID. Read-only. To find prospect_pool_id: list_prospect_pools → match by name. |
| list_prospect_poolsA | List all prospect pools with their stages. Read-only. Resolves pool names to IDs for add_prospect. Returns each pool's
|
| list_close_reasonsA | List all close reasons for job openings. Read-only. Resolves close reason names to IDs for hire_application and update_job_opening. |
| get_tracking_linkA | Get a tracking link by its token. Read-only. Returns the link's source_id, referrer_id, job_id, job_board_id and
job_post_id, plus |
| list_user_rolesA | List all user roles in the organization. Read-only. Resolves role names to IDs for add_job_permission and add_future_job_permission. Only roles with role_type 'job_admin' can be granted on jobs. |
| list_degreesA | List degree types (Bachelor's, Master's, PhD, etc.). Read-only. Resolves degree names to IDs (degree_id) for add_education. Each item is a custom field option with id and name. |
| list_disciplinesA | List academic disciplines (Computer Science, Business, etc.). Read-only. Resolves discipline names to IDs (discipline_id) for add_education. Each item is a custom field option with id and name. |
| list_schoolsA | List schools for education records. Read-only. Resolves school names to IDs (school_id) for add_education. Each item is a custom field option with id and name. |
| candidates_needing_actionA | Find candidates that need attention — stale apps, missing scorecards. Read-only. Users say "what needs my attention?" or "who's been sitting too long?" Pass job_id for one job (list_jobs → match by name) or omit for all active applications. Returns stale applications sorted by urgency and interviews awaiting feedback, with the interviewers whose scorecards are still missing. |
| pipeline_summaryA | Complete pipeline view for a job — candidates grouped by stage. Read-only. Users say "show me the pipeline for Backend Engineer" or "how many candidates are in each stage." To find the job_id: list_jobs → match by name. Returns the job's interview stages in pipeline order, each with its active candidates: names, source, days in the current stage, and days since last activity. One call replaces 5-10 sequential API calls. |
| stale_applicationsA | Applications with no activity for N days, sorted by stalest. Read-only. Users say "who's been sitting untouched?" Use the results with bulk_reject for pipeline cleanup. Pass job_id (list_jobs → match by name) to filter to one job. Each row includes the current stage and job name. |
| pipeline_metricsA | 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 interview stage in pipeline order: how many applications ever reached it, how many are there now, % of all applications, stage-to-next conversion, and average days spent in the stage (from stage history). |
| source_effectivenessA | 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, rejected, hired and hire rate per source, with each source's strategy (e.g. Referral). |
| time_to_hireA | 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 from application to hire. The hire date is the accepted offer's resolved date when available, otherwise the application's last activity. |
| bulk_advanceA | Advance multiple applications to the next stage. Write operation — rate-limited. Users say "move everyone past phone screen forward." Get application_ids from pipeline_summary or list_applications. Each application moves from its current stage to the next one on its job's interview plan. Optionally pass from_stage_id (list_job_stages_for_job → match by name) to only advance applications currently in that stage — others are skipped. Rejected, hired or prospect applications are skipped. Processes sequentially with rate-limit delays. |
| bulk_rejectA | Reject multiple applications in one call. Write operation — rate-limited. Users say "reject everyone who's been inactive for 30 days on the Backend role." First use stale_applications to identify the targets, then pass their application_ids here. rejection_reason_id is required: list_rejection_reasons → match by name. To email candidates, set rejection_email=true and pass email_template_id (list_email_templates). Processes sequentially with rate-limit delays. |
| bulk_tagA | Tag multiple candidates in one call. Write operation — rate-limited. Users say "tag all the candidates from the hiring event." Pass candidate_ids from search or pipeline tools and a tag_name (created automatically if new). Candidates who already have the tag are skipped. Processes sequentially with rate-limit delays. |
| search_candidates_by_emailA | Look up a candidate by exact email address. Read-only. Use when the user provides an email instead of a name. Matches any email on the candidate's profile and returns the candidate record. For their applications, follow up with list_applications(candidate_id=...). For name-based lookup, use search_candidates_by_name. |
| search_candidates_by_nameA | Find candidates by name. Read-only — the starting point for most workflows. Users always refer to candidates by name, not ID. Use this first whenever a user mentions a candidate, then list_applications(candidate_id=...) to find their application IDs (candidate records don't include applications). Case-insensitive substring match — "Sarah" finds "Sarah Chen", "Sarah O'Brien", etc. Greenhouse has no name filter, so this scans up to max_pages × per_page candidates; if has_more is true, pass next_cursor to keep scanning. |
| download_attachmentA | 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., get_candidate's or get_application's attachments array). Attachment URLs are time-limited — if a download fails, fetch the record again for a fresh URL. |
| read_candidate_resumeA | 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 recently uploaded resume across all the candidate's applications. For batch reading, use batch_read_resumes. |
| fetch_new_applicationsA | Applications since a date, grouped by job — the daily digest. Read-only. Users say "what new applications came in since yesterday?" Pass since as an ISO date (applications created on or after it). Optionally filter to one job with job_id (list_jobs → match by name). Returns applications grouped by job with candidate names, sources, stages, and screening answers. |
| screen_candidateA | Full screening package for one candidate application. Read-only. Users say "screen Sarah for the Backend role" or "give me the full picture." To get application_id: search_candidates_by_name → list_applications (candidate_id=...) → match the application to the job name. Returns profile, resume text, location, screening answers, job description, and application history (with job names and rejection reasons) in one call. |
| batch_read_resumesA | Download and extract resume text for a list of candidates. Read-only. Use after narrowing candidates with other sourcing tools. Pass candidate_ids from search_pipeline_candidates or scan_all_candidates. Uses each candidate's most recent resume across all their applications. Full resume text reveals career trajectory, scope of work, and skills that structured data doesn't capture. |
| scan_all_candidatesA | Database-wide candidate search by structured fields. Read-only. Like search_pipeline_candidates but searches the full database, not just specific pipelines. Use when candidates might be in unexpected pipelines. Pass updated_after to limit scope on large databases (title, company and experience filters fetch employment history for every scanned page). Follow up with batch_read_resumes to validate matches. |
| scan_pipeline_resumesA | Search resume text in pipelines for skills and qualifications. Read-only. Users say "find Rust engineers in our pipelines" or "search for distributed systems experience." The primary sourcing tool — ~90% of candidate data lives in resumes. Pass job_ids (list_jobs → get IDs for similar roles). Supports boolean search: keywords (OR), required_keywords (AND), exclude_keywords (NOT with word-boundary matching). |
| search_pipeline_candidatesA | Search pipelines by structured fields — title, company, education, tags. Read-only. Users say "find VP-level candidates in our pipelines" or "who do we have from Google?" Pass job_ids (list_jobs → get IDs for similar roles). Best when structured data (employment and education history) is populated. If few results, switch to scan_pipeline_resumes for resume-text search. Combine with batch_read_resumes to verify skill matches. |
| post_candidateA | Submit a candidate via the Ingestion API (partner integration). Write operation. For internal candidate creation (as recruiter/admin), use create_candidate and create_application instead. This is the partner/integration endpoint. |
| retrieve_ingestion_jobsA | List jobs visible to the integration partner. Read-only. Partner-scoped version of list_jobs. Returns only jobs the integration has been granted access to. |
| retrieve_prospect_poolsA | List prospect pools via the Ingestion API. Read-only. Partner-scoped version of list_prospect_pools. |
| retrieve_ingestion_candidatesA | List candidates submitted through the Ingestion API. Read-only. Shows candidates this integration has submitted. For the full candidate database, use list_candidates instead. |
| post_tracking_linkB | Create a tracking link for source attribution on a job. Write operation. Generates a URL that attributes future applications to this source. |
| retrieve_current_userA | Get the current integration partner user. Read-only. Returns the API user associated with the Ingestion API credentials. |
| get_boardA | Get job board metadata — name, content, departments, offices. Read-only. Returns the public-facing board info. For internal job management, use list_jobs instead. |
| get_board_jobA | Get a published job with optional application questions. Read-only. For internal job details (hiring team, custom fields), use get_job instead. |
| list_board_jobsA | List all published jobs on the public job board. Read-only. Returns jobs visible to external candidates. For internal job data with pipeline info, use list_jobs instead. |
| get_board_departmentB | Get a department from the public job board. Read-only. |
| list_board_departmentsA | List departments on the public job board. Read-only. For internal department management, use list_departments instead. |
| get_board_officeB | Get an office from the public job board. Read-only. |
| list_board_officesA | List offices on the public job board. Read-only. For internal office management, use list_offices instead. |
| get_prospect_post_sectionB | Get a prospect post section by ID. Read-only. |
| list_prospect_post_sectionsA | List prospect post sections on the job board. Read-only. |
| list_board_degreesA | List degree types for board application forms. Read-only. Provides the degree dropdown options shown to external applicants. |
| list_board_disciplinesA | List academic disciplines for board application forms. Read-only. Provides the discipline dropdown options shown to external applicants. |
| list_board_schoolsA | List schools for board application forms. Read-only. Provides the school dropdown options shown to external applicants. |
| submit_applicationA | 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. |
| webhook_create_ruleA | Create a webhook routing rule. Write operation. Use webhook_list_events to see available event types. Set event_type to '*' to match all events, or a specific type like 'candidate_stage_change'. Use webhook_test_rule to dry-run after creating. |
| webhook_delete_ruleB | Delete a webhook routing rule. Write operation. To find rule_id: webhook_list_rules. |
| webhook_list_rulesA | List all webhook routing rules. Read-only. Returns all configured rules with their event types, actions, and status. |
| webhook_update_ruleB | Update a webhook routing rule. Write operation. To find rule_id: webhook_list_rules. |
| webhook_list_eventsA | List all Greenhouse webhook event types with descriptions. Read-only. Reference for webhook_create_rule — shows available event types like 'candidate_stage_change', 'hire_candidate', 'new_candidate_application', etc. |
| webhook_list_recentB | List recent webhook events received by the receiver. Read-only. Shows the latest events captured by the webhook receiver, useful for debugging and verifying webhook delivery. |
| webhook_test_ruleA | Dry-run a rule against the most recent matching event. Read-only. Shows what would happen without actually executing the action. Use after webhook_create_rule or webhook_update_rule to verify behavior. To find rule_id: webhook_list_rules. |
| webhook_setup_guideA | Generate webhook configuration instructions for Greenhouse. Read-only. Produces the exact values to enter in Greenhouse UI (Configure > Dev Center
|
Prompts
Interactive templates invoked by user choice
| Name | Description |
|---|---|
No prompts | |
Resources
Contextual data attached and managed by the client
| Name | Description |
|---|---|
No resources | |
TDQS
Scored across 187 tools
Several tools have overlapping purposes, such as multiple candidate search/scan tools (search_candidates_by_name, search_candidates_by_email, list_candidates, scan_all_candidates, search_pipeline_candidates, scan_pipeline_resumes) and overlapping analytics (pipeline_metrics vs source_effectiveness, candidates_needing_action vs stale_applications). Descriptions provide cross-references and clarifications, but the sheer volume and similarity of some tools still create misselection risk.
Tool names mostly follow a consistent snake_case verb_noun pattern (e.g., list_jobs, get_candidate, create_application, update_interview). A few exceptions exist, such as noun-phrase names (pipeline_summary, candidates_needing_action) and prefixed families (webhook_*, board_*), but the overall convention is predictable and readable.
187 tools is an extreme mismatch for a single MCP server, far exceeding the 50+ threshold that indicates poor scoping. Many tools are thin CRUD wrappers or context-specific duplicates (e.g., board vs internal vs ingestion versions) that could be consolidated into fewer, more versatile tools.
The tool surface covers the entire Greenhouse ATS domain comprehensively: candidates, applications, jobs, interviews, offers, approvals, users, departments, offices, custom fields, tags, sources, rejection reasons, EEOC, webhooks, and ingestion. CRUD lifecycle operations are present for most resources, with no obvious dead ends for core workflows.