MCP App Store
by KeenEthics

Overview

Connect Gem with ChatGPT to bring your recruiting data to where you work. With the Gem MCP, you can query hiring analytics, pull applications, rediscover past talent, and take bulk actions in natural language.

Tools

add_note_to_person

ChatGPT
Add a note to a person's activity feed. Pass person_ext_id (e.g. from search, search_people, or get_person) and the note content. content is plain text by default; set content_format='html' to pass sanitized rich formatting (<p>, <br>, <b>, <ul>/<li>, <a href>). To @-mention a teammate, put an @[user_id] token (the user_id from search_users) inline in content — they're notified and start following the person. A visible note can also notify teammates who follow the person and, for eligible Greenhouse teams, sync to the ATS activity feed. Returns the person's ext_id and the new note's ext_id.

archive_project

ChatGPT
Archive an existing project, or restore an archived one. Pass the project's project_ext_id (e.g. from search or get_project); archived defaults to true to archive. This is reversible — call again with archived=false to unarchive and restore the project. Returns the project_ext_id and the project's new is_archived state. Archiving hides the project from active views but does not delete it or its candidates.

archive_sequence

ChatGPT
Archive an outreach sequence template, or unarchive it to restore it (pass archived=false). Only sequence templates can be archived — not drafts or individual sequence instances. Archiving is reversible. Consider get_sequence first to see how many people are still actively enrolled. Returns the sequence's ext_id and its resulting is_archived state.

delete_widget

ChatGPT
Permanently delete a widget from its dashboard. The widget is removed immediately and cannot be recovered. Returns the deleted widget's ext_id and deleted=true.

edit_project_enrollment

ChatGPT
Add candidates to or remove them from an existing project. Pass the project's project_ext_id (e.g. from search or get_project) plus add_person_ext_ids and/or remove_person_ext_ids (person ext_ids from search, search_people, or get_person). Returns the project_ext_id, how many were added and removed, and the skipped ext_ids. Use save_project to create the project itself or edit its name/description.

edit_sequence_enrollment

ChatGPT
Enroll people into an existing outreach sequence and/or unenroll them. Pass sequence_ext_id (owned by the current user) plus add_person_ext_ids and/or remove_person_ext_ids (person ext_ids, e.g. from search or search_people). Returns how many were newly added, how many removed, a skipped list pairing each person NOT acted on with the reason, and any warnings about the people who were. Enrolling into a reusable template copies it into a new sequence, so the returned sequence_ext_id may differ from the one passed in. Use save_sequence first to create the sequence shell.

edit_sequence_stages

ChatGPT
Edit one outreach stage (an email/message step) of a sequence owned by the current user — its subject, body_html (rich-text body), stage_type, and wait_days — addressed by index (use N+1 to append a new follow-up). Pass the version from get_sequence: the edit is rejected if the sequence changed since you read it, and a successful edit returns the new version to chain the next edit. An unknown merge token is rejected; text that only looks suspect comes back in warnings. Returns the affected index, a created flag, the new version, and any warnings. Use save_sequence to create the sequence first, and get_sequence to read the stages and current version.

get_application

ChatGPT
Look up one application (a candidate on a specific job) by ext_id — status, stage, stage_entry, gem_status (the Talent Pipeline's computed next-step status and SLA health, e.g. NEEDS_DECISION / MISSED_TARGET; null for closed applications and for ATSes without support), source, job ref, rejection (its reason_type says whether we rejected them or they declined), and form answers: the full evaluation record behind an application. Get an ext_id from a person's applications (get_person) or from search_applications. Use fields for interviewer scorecards and the offer. The response is {found, entity} — check found before reading entity; a missing row and a no-access row both return found: false.

get_dashboard

ChatGPT
Look up one dashboard by ext_id — name, owner, link, and its widgets in display order. Each widget lists the metric it reports and how it's sliced (metric, visualization, stages, breakdowns, time granularity) plus its grid size — width ("1"/"2"/"3" columns or "max" for full-bleed) and height (row span), both settable back via save_widget. Use it to see what a dashboard tracks and how it's laid out, then call query_metrics to compute those numbers. A dashboard's ext_id is what search (kind=dashboard) returns, and the id in a gem.com /dashboard/<ext_id> URL. The response is {found, entity} — check found before reading entity; a missing row and a no-access row both return found: false.

get_job

ChatGPT
Look up one job by ext_id — title, status, requisition id, ATS, department/office, and link. Cross-ATS. For Gem ATS jobs also returns openings ({ext_id, name} → get_opening) and the pipeline stages ({ext_id, name, index} → search_applications's stage_ids). Use fields for the job's custom fields, its job_posts (posting descriptions), and/or its hiring_team (hiring managers, recruiters, coordinators, sourcers, each {name, email}). A job's ext_id is what search / search_jobs return, and the id in a gem.com /ats/jobs/<ext_id> URL. The response is {found, entity} — check found before reading entity; a missing row and a no-access row both return found: false.

get_metrics_catalog

ChatGPT
List the metrics and dimensions this team can report on with query_metrics. Call this first to get valid metric and dimension ids. Returns groups of co-queryable metrics: metrics in the same group share a data source, so they can be combined in one query_metrics call and grouped or filtered by that group's dimensions, while metrics from different groups need separate calls. Each metric carries its id, unit, and valid aggregations; each dimension marks whether it's filterable or group-by only. Groups flagged requires_date_range take a date_range from the returned date_ranges. Also returns pipeline_stages — the team's normalized stages in order, each with an id (the STAGE_TYPE:name string) for query_metrics's stages / exclude_stages / cohort_entry_stage and a name for search_people's ats_pipeline_stage — and widget_metrics, the separate metric vocabulary save_widget accepts, each mapped to the query_metrics id it corresponds to. Pass groups to slim a large catalog to just the areas you need.

get_opening

ChatGPT
Look up one opening (headcount/requisition) by ext_id — name, status, hire type, department, locations, job levels, associated jobs, target dates, and link. Use fields for its custom fields. Gem ATS only: other ATSes return found: false. ext_id is an opening id, e.g. from a gem.com URL /ats/openings/<ext_id>. The response is {found, entity} — check found before reading entity; a missing row and a no-access row both return found: false.

get_person

ChatGPT
Look up one candidate by ext_id — name, current title, company, school, emails, phone numbers, and links, plus optional fields (full work history, education, custom fields, applications, activity timeline, sequence responses, and resumes — presigned download URLs valid for 7 days for the candidate's resume files, including the LinkedIn PDF imported at sourcing time). Feed an application's ext_id into get_application for its scorecards. A candidate's ext_id is what search (kind=person) and search_people return, and the id in a gem.com /candidate/<ext_id> URL. The response is {found, entity} — check found before reading entity; a missing row and a no-access row both return found: false.

get_project

ChatGPT
Look up one project by ext_id — name, description, owner, link, type, privacy, archived status, and people_count (candidates in the project). Use fields for its custom fields and/or its people (the candidates in the project). A project's ext_id is what search (kind=project) returns, and the id after -- in a gem.com /projects/--<ext_id> URL. The response is {found, entity} — check found before reading entity; a missing row and a no-access row both return found: false.

get_saved_report

ChatGPT
Look up one saved analytics report (Pipeline Analytics or Outreach) by ext_id — its name, type, owner, link, and a ready-to-run query_metrics payload translated from the report's saved configuration. Run that payload through query_metrics to reproduce the report's numbers. For Outreach reports the payload's metrics are the standard activity/cohort family (the report may display a subset). Check fully_reproducible/caveats: when false, the report uses a knob query_metrics can't express and the payload is a best-effort approximation. A saved report's ext_id is the reportId in a gem.com analytics report URL (e.g. /pipeline-stats?reportId=<ext_id> or /outreach-stats?reportId=<ext_id>). The response is {found, entity} — check found before reading entity; a missing row and a no-access row both return found: false.

get_sequence

ChatGPT
Look up one outreach sequence by ext_id — name, status, whether it is a reusable template (is_template) and whether it is archived (is_archived), owner, link, a version (the sequence's edit version — pass it to edit_sequence_stages, which rejects edits made against a stale version), and its ordered stages (index, stage_type channel, subject, body as plain text, and days_after cadence). Pass fields for two opt-in sections: enrollment — its recipients with each one's current stage, next send time, reply status, and stop reason (capped, with the full total); and personalization — the per-person AI {gem_ai:} values with a reviewed status (capped, with the full total), where reviewed=false means the value has not yet been approved to send. A sequence's ext_id is what search (kind=sequence) returns, and the id in a gem.com /sequence/<ext_id> URL. The response is {found, entity} — check found before reading entity; a missing row and a no-access row both return found: false.

get_sequence_tokens

ChatGPT
List the merge tokens available for writing a sequence stage's subject or body on this team. Call this before authoring a stage so you know which {{tokens}} you can use. Each token's key is the field name that goes inside the braces (write {{first_name}} to insert the candidate's first name), with a human label and a category: Person (the candidate's profile), Custom (the team's custom person fields), Computed (filled at send time, e.g. day_of_week), Job (recruiter_name, only when the team has a connected ATS), and AI, listed only when Gem AI is enabled for the team — a freeform per-person token: write {{gem_ai: <your instruction>}} in the body, then set each person's value with set_sequence_personalization (not pulled from a fixed field). Feed the keys into edit_sequence_stages.

get_tasks

ChatGPT
List the current user's actionable to-dos: their upcoming scheduled interviews ('what interviews do I have this week?') and the scorecards they still owe. Pass kind ('interview' or 'scorecard') to filter, or omit for both; soonest first. Each task carries a title, gem_link, the candidate and job, and an application_ext_id to feed into get_application. Interview tasks also carry location, duration_minutes, video_conferencing_url (present only when Gem created the meeting), and interviewers — the full panel with each one's name, email, and response_status. Scorecard tasks also include the questions to fill out (each with text, answer_type, options, and whether it's required). This is the 'what's on my plate' tool — it needs no candidate or job id.

get_widget

ChatGPT
Look up one dashboard widget by ext_id (a widget_id from get_dashboard) — its title, visualization, metric, parent dashboard, and a ready-to-run query_metrics payload translated from the widget's saved configuration. Run that payload through query_metrics to reproduce the widget's numbers. For Outreach widgets the payload's metrics are the standard activity/cohort family (the widget may display a subset). Check fully_reproducible/caveats: when false, the widget uses a knob query_metrics can't express and the payload is a best-effort approximation. TEXT widgets have no metric; they return text_content, the full authored body as HTML. get_dashboard carries only a truncated content_preview, so read the body here and pass it back as save_widget's text_content when copying a dashboard. The response is {found, entity} — check found before reading entity; a missing row and a no-access row both return found: false.

query_metrics

ChatGPT
Run a recruiting-analytics query and get back an aggregated {columns, rows} table. Use this for reporting and any 'how many / what rate / trend over time' question — pipeline health, pass-through, time-in-stage, outreach, offers, hires. Call get_metrics_catalog first for the metric and dimension ids this team can use; all metrics in one call must come from the same catalog group, and Pipeline Analytics accepts only one metric per query (request candidates / time-in-stage / pass-through separately).

save_dashboard

ChatGPT
Create a new analytics dashboard or edit an existing one's metadata — name, description, emoji, visibility ('PUBLIC' for the whole team or 'PRIVATE' for owner + link), date_range (the relative time window it opens in, e.g. 'last_90_days'), and filter_terms (a JSON-string array of dashboard-wide filters applied to every widget; pass query_metrics-style {dimension_id, ids} terms and they're converted to the stored form on save, like save_widget's filter_terms). Omit dashboard_ext_id to create a fresh dashboard (new ones default to PUBLIC and the last 90 days); pass one — e.g. an ext_id from search — to update, and only the fields you include change. Returns the dashboard's ext_id, name, and a created flag (true when a new dashboard was made). This sets up the dashboard shell only; it does not add or configure widgets.

save_project

ChatGPT
Create a new sourcing project or edit an existing one's metadata (name, description, privacy). Omit project_ext_id to create; pass it to update. Returns the project's ext_id, name, privacy_type, and a created flag. Sets up the project shell only; it does not add or remove candidates.

save_sequence

ChatGPT
Create a new outreach sequence or rename an existing one. Omit sequence_ext_id to create a fresh sequence (set is_template to make it a reusable template); pass one — e.g. an ext_id from search — to rename that sequence. Returns the sequence's ext_id, name, and a created flag (true when a new sequence was made). This sets up the sequence shell only; it does not add or edit outreach stages or recipients.

save_widget

ChatGPT
Create a chart widget on a dashboard, or edit an existing one. Core config is title, metric, visualization, time_granularity, and aggregation_type; breakdowns go in group_breakdown_types and stage_types_and_names, and outreach metrics use outreach_breakdown / outreach_group_by / outreach_activities — each field's accepted values are documented on the field. filter_terms and outreach_filter_terms accept query_metrics-style {dimension_id, ids} terms (as in get_widget's query_metrics.filters) and convert them to the stored dashboard format on save; visualization_options is a JSON-string object of chart options. []/{} clears any of them. Specialized modes: text_content for a TEXT widget, benchmark_statistic_type + benchmark_categories for an industry-standard overlay, the passthrough_ fields for a PASSTHROUGH_RATE / TIME_IN_STAGE cohort, and outreach_funnel_stages for a CANDIDATE_COHORTS_ widget. Size and arrange the widget with width (1/2/3 columns or "max" for full-bleed), height (row span), and position (0-based slot among the dashboard's widgets); new widgets otherwise append in creation order at a default size, and get_dashboard reports each widget's current size and order. Omit widget_ext_id and pass dashboard_ext_id (e.g. from search or save_dashboard) to create; pass widget_ext_id to update, and only the fields you include change. Returns the widget's ext_id, its dashboard_ext_id, and a created flag.

search_applications

ChatGPT
List the candidates in one job's pipeline. Requires job_id — a job ext_id from search or get_job. Returns shallow application summaries (ext_id, status, stage, stage_id, stage_entry, gem_status — the Talent Pipeline's computed next-step status and SLA health {status, sla_status, associated_ts_ms} for open applications; null for closed ones and for ATSes without support — candidate name/email/location with a get_person-compatible ext_id when person-linked, applied/closed dates, rejection, gem_link, and candidate_tags), newest first; active applications only by default — set include_rejected / include_hired to widen, or stage_ids to filter to stages. Filter by application_statuses (e.g. SCHEDULED, NEEDS_DECISION), sla_statuses (["MISSED_TARGET"] = stalled past the team's SLA target, auto-excluding already-scheduled candidates), or candidate_tags (whole tag names, case-insensitive; every result carries its own tags, so an unfiltered call shows which ones the job uses); with these filters total_count counts only matching applications. Page with limit/offset while has_next_page is true. Pass fields for scorecards or the offer on every row instead of calling get_application per application (limit caps at 25 with scorecards); feed an ext_id into get_application for one record's form answers. For candidates across many jobs use search_people; for pipeline counts use query_metrics.

search_jobs

ChatGPT
Find jobs by criteria — turn a job name or req id into the ext_id other tools take, or browse a team's jobs. query matches job title and requisition id; omit it to list all open jobs, and filter by department or office (each with a recursive variant covering sub-departments / child locations), or set following to return only jobs you follow. Returns shallow job stubs (ext_id, title, status, requisition_id, department, offices, gem_link), best match first; page with limit/offset while has_next_page is true. Pass fields for the job's hiring_team (hiring managers, recruiters, coordinators, sourcers, each {name, email}) on every row. Feed an ext_id into get_job for the full record or search_applications for that job's candidates; for job counts or rates use query_metrics.

search_people

ChatGPT
Find candidates by attribute across CRM and ATS — title, company, skills, location, years of experience, pipeline stage, scorecards, and contact recency. Filters combine with AND; page with page while has_next_page is true. By default returns only candidates not in an active pipeline and not yet hired (available for fresh outreach) — set include_open_applications to widen. Feed a result's ext_id into get_person. The result also carries a top-level gem_link, a shareable gem.com link that reopens the whole search in Gem's UI. Use search if you already know the person's name, or query_metrics to count or aggregate instead of paging here.

search_users

ChatGPT
Resolve a teammate to their ATS ID (used for analytics queries and filters that rely on it) and Gem ID (used for tagging in notes). Search by name or email. Each hit returns display_name, email, user_ats_id, and user_id.

set_sequence_personalization

ChatGPT
Set per-person AI personalization values for a sequence's {{gem_ai: <prompt>}} tokens — the custom text each recipient sees in place of a token. Pass sequence_ext_id (owned by the current user) and personalizations, a list of {person_ext_id, prompt, value} where prompt matches a {{gem_ai: <prompt>}} token placed in a stage body via edit_sequence_stages. Returns how many were set and a skipped list. Every value is stored UNREVIEWED — it does not send until a human reviews and approves it.

submit_mcp_feedback

ChatGPT
Send feedback about these Gem tools to the team at Gem that builds them — a bug, a missing capability, or confusing behavior. Say what you were trying to do and what went wrong; don't include candidate names or other personal data. Use only when the user explicitly asks to send feedback or report a problem to Gem.

whoami

ChatGPT
Return the Gem user this session is authenticated as: user_id, team, email, client id, and the team's ATS (e.g. 'Gem ATS', 'Greenhouse'). Use it to confirm whose data the other tools read, or to resolve who "me" / "my team" is before a filtered search or task lookup.

add_note_to_person

Claude

archive_project

Claude

archive_sequence

Claude

delete_widget

Claude

edit_project_enrollment

Claude

edit_sequence_enrollment

Claude

edit_sequence_stages

Claude

get_application

Claude

get_dashboard

Claude

get_job

Claude

get_metrics_catalog

Claude

get_opening

Claude

get_person

Claude

get_project

Claude

get_saved_report

Claude

get_sequence

Claude

get_sequence_tokens

Claude

get_tasks

Claude

get_widget

Claude

query_metrics

Claude

save_dashboard

Claude

save_project

Claude

save_sequence

Claude

save_widget

Claude

search_applications

Claude

search_jobs

Claude

search_people

Claude

search_users

Claude

set_sequence_personalization

Claude

submit_mcp_feedback

Claude

whoami

Claude

Capabilities

Writes

Example Prompts

Click any prompt to copy it.

App Stats

64

Tools

3

Prompts

ChatGPT, Claude

Platforms

Works with

ChatGPT
Claude

Data refreshed daily