AI Interview Agents MCP Server
The AI Interview Agents MCP Server enables you to manage an end-to-end AI-driven hiring pipeline via natural language from any MCP client, covering everything from role creation to scored interview reports.
Role Management
List existing job roles and create new ones from job descriptions
Set up dedicated screening roles with skills, experience, location, and work mode requirements
Candidate & CV Processing
Parse CV/resume files (PDF, DOCX, up to 20 per call) with OCR fallback to extract candidate info
Add parsed candidates to screening roles and reassign candidates between roles
CV Screening & Ranking
Trigger async AI scoring of CVs against a job description
Retrieve ranked results with scores (0–100), verdicts (strong/possible/weak/reject), matched/missing skills, and location fit
Interview Scheduling & Management
Schedule AI-driven voice interviews (screening, technical, or HR types; multilingual support)
Use dry-run mode to preview configuration before sending invites or consuming quota
Reschedule, cancel, and send reminder emails for interviews
Schedule top-ranked screened candidates directly for interviews
Question Preview
Generate and preview AI-tailored interview questions before committing to a schedule
Reporting & Pipeline
List interviews with filters (role, candidate, status, date)
Retrieve full interview details including transcripts and feedback
Access scored reports with analysis summaries, strengths, weaknesses, and recommendations
View the candidate pipeline funnel (invited/scheduled/completed/no-show) per role
Provides authentication integration with Firebase, enabling secure user sign-in and bearer token validation for API requests.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@AI Interview Agents MCP Server List all candidates for the senior developer role."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
AI Interview Agents — MCP Server
The official Model Context Protocol server for AI Interview Agents, a voice-AI hiring platform. It lets any MCP client (Claude, Cursor, custom agents) drive the recruiting workflow in natural language: create roles, screen CVs, schedule and manage candidate interviews, and read back scored reports with transcripts.
The live voice interview itself is out of scope here (that runs on a separate real-time service). This server triggers interviews and reads back the results.
What it exposes
Roles — list your roles, or create one from a job description.
Candidates & CVs — parse dropped CV/PDF files, normalize messy pasted candidate lists (names, emails, phone numbers, experience, skills), and reassign candidates between roles.
Interviews — schedule interviews (with a
dry_runmode that normalizes and previews without sending anything or consuming quota), reschedule, cancel, and send reminders.Reports — read the candidate pipeline and pull back scored interview reports with transcripts.
Related MCP server: Spec-Driven IntelliMatch / iSuite MCP
Use the hosted server (recommended)
The server runs remotely with OAuth sign-in. Point any Streamable-HTTP MCP client at:
{
"mcpServers": {
"ai-interview-agents": {
"type": "streamable-http",
"url": "https://mcp.aiinterviewagents.com/mcp"
}
}
}Your client discovers the auth flow automatically via /.well-known/oauth-protected-resource and signs you in with your AI Interview Agents account. It is also listed in the official MCP Registry as com.aiinterviewagents/interviews.
Run it locally (stdio)
pip install -e .
export AIIA_FIREBASE_TOKEN="<your token>" # or: aiia-mcp login
aiia-mcpAIIA_BACKEND_URL overrides the API base if you are pointing at your own deployment.
How auth works
The server holds no account secrets. Each request carries the user's own Firebase ID token, forwarded to the backend as a bearer token — the same trust path as the web app. For the hosted transport, an OAuth layer (dynamic client registration + PKCE) bridges MCP clients to Firebase sign-in.
Development
pip install -e ".[dev]"
pytest
ruff check .License
MIT — see LICENSE.
Available Tools
18 toolsadd_screening_candidatesA
Attach parsed CVs to a screening as candidates, ready to be scored.
Pass the rows returned by parse_cvs straight through — each
{"identity": {...}, "details": {...}} row is reshaped automatically into
what the backend needs. Already-flat dicts ({firstName, lastName, email,
summary, parsedResumeData, number, location}) also work.
Email is NOT required here — screening scores a CV, it doesn't message
anyone. CVs with no email are kept and given an unroutable placeholder so
they still rank; the response's 'withoutEmail' count tells you how many.
Those rows CANNOT be scheduled later until a real email is added — surface
that number to the user.
Returns {savedCount, skippedEmpty (CVs with no readable content),
withoutEmail, candidates}. After this, call run_screening(role_id).
Inputs: role_id (required), candidates (required).
cancel_interviewADestructive
Cancel a scheduled interview. Destructive — meeting and candidate rows are deleted.
ASK BEFORE CALLING if the user said "that interview" / "Priya's"
/ anything ambiguous and you don't have a specific meeting_id from
a prior list_meetings result. Call list_meetings first to surface
candidates, then confirm with the user which meeting they mean.
Cancelling the wrong meeting cannot be undone in-band — the
candidate has to be rescheduled from scratch.
Inputs: meeting_id (required).
create_screening_roleA
Create a Screening — a role to rank CVs against a JD before spending any interview credit. Returns {"roleId": , ...}; keep that roleId for the rest of the flow.
THE SCREENING FLOW (call these tools in order):
1. create_screening_role ← you are here
2. parse_cvs(files=...) — extract candidates from resume files
3. add_screening_candidates(role_id, candidates=<parse_cvs rows>)
4. run_screening(role_id) — starts async CV-vs-JD scoring
5. get_screening_results(role_id) — poll until scored, read the ranking
6. schedule_screened_candidates(role_id, candidate_ids) — invite the good ones
FIELDS:
- name: the screening / role title (required, e.g. "Senior Backend Engineer").
- job_description: paste the full JD text if you have it — it drives the
score most. Optional but strongly recommended.
- must_have_skills vs nice_to_have_skills: skills the role weighs heavily
vs would-be-nice. Neither AUTO-REJECTS anyone — they shape the LLM
score and the matched/related/missing breakdown.
- experience: free text, e.g. "5+ years".
- location + work_mode: work_mode is 'remote', 'onsite', or 'hybrid'.
Location is a soft signal only (a remote role ignores it); nobody is
dropped for being in the wrong city.
- additional_requirements: free text the model folds into scoring, e.g.
"valid work visa", "bachelor's degree", "AWS certified".
- language: 'en', 'hi', or 'ar'. company_name: optional.
This creates a role record (screening_enabled). If the user already has a
screening for this opening, call list_screening_roles first and reuse its
roleId instead of making a duplicate.
Inputs: name (required), language, location, work_mode, +6 more.
generate_questionsARead-only
Generate interview questions using AI. Read-only — does not create a role or schedule anything. Use to preview what the bot will ask before committing to schedule_interview.
interview_type: 'screening' or 'technical'.
language: 'en', 'hi', 'ar'.
Inputs: position (required), interview_type (required), required_skills (required), duration, +4 more.
get_meetingARead-only
Full details of a single meeting including transcript and feedback.
meeting_id accepts the UUID or the integer primary key.
Inputs: meeting_id (required).
get_pipelineARead-only
Pipeline view (invited / scheduled / completed / no-show) for a role.
Use to answer 'how is the hiring going for this role'.
Inputs: role_id (required).
get_reportARead-only
Scored interview report: analysisSummary, strengths, weaknesses, recommendations, averagePercentage, nextSteps.
Returns status=processing if the report hasn't generated yet.
Inputs: meeting_id (required).
get_screening_resultsARead-only
Read a screening's ranked candidates (the poll for run_screening).
Returns {roleId, count, role:{name, mustHaveSkills, niceToHaveSkills,
location, workMode, additionalRequirements}, candidates:[...]}, candidates
sorted best-first by screeningScore. Each candidate:
{id, name, email, hasEmail, phone, position, experienceYears, location,
locationFit ('remote'|'in_region'|'other'|null), screeningScore (0-100),
screeningVerdict ('strong'|'possible'|'weak'|'reject'), screeningStatus,
reason, matchedSkills, relatedSkills, missingSkills, status, screenedAt}.
DONE-SIGNALS (scoring is async): a candidate is finished when
screeningStatus is 'scored', 'hard_filtered', 'overridden', or 'error',
and still pending at 'not_screened'. The whole screening is done when
every row has left 'not_screened' (or screenedCount == candidateCount in
list_screening_roles). If rows are still 'not_screened', wait and call again.
To schedule, take the 'id' of each candidate you want and pass them to
schedule_screened_candidates. Skip rows where hasEmail is false — they
need a real email first.
Results are capped at `limit` (default 100, top by score) and each
'reason' is truncated to keep the response small; raise limit if you
need more rows.
Inputs: role_id (required), limit.
list_meetingsARead-only
List interviews for the authenticated HR user.
Optional filters:
- role_id, candidate_id — narrow to a specific role / candidate
- status — one of: Scheduled, Completed, Cancelled, Expired
- scheduled_after — ISO datetime or YYYY-MM-DD; only meetings
scheduled on/after this point. Use for "last week" / "this
month" queries (compute the cutoff client-side).
Returns paginated meeting records with totals for completed and
cancelled. The 'role_name' field on each row is the easiest way to
surface 'recent roles' when the user hasn't named one yet.
Rows are summaries: transcripts and full report payloads are
stripped to keep responses small — use get_meeting / get_report
for one meeting's full detail.
Inputs: page, size, status, role_id, +2 more.
list_rolesARead-only
List the authenticated HR user's roles (job postings / openings).
Use this whenever the user hasn't named a role and you need to ask
"which role should I schedule against?" — surface 2-3 recent ones
from the response by 'name' / 'position'. Also use for queries like
"what roles do I have" or "what openings am I hiring for".
Returns: {"data": [{roleId, name, position, experience, skills,
evaluationFocus, interviewType, jobDescription, language, ...}]}.
Inputs: no named parameters.
list_screening_rolesARead-only
List the authenticated user's screenings (CV-screening roles).
Use this to find an existing screening's roleId (so you don't create a
duplicate), or to report progress. Each row carries:
{roleId, name, position, location, workMode, candidateCount,
screenedCount, topMatches (score >= 60), scheduledCount, createdAt}.
screenedCount == candidateCount means scoring has finished for that
screening (the role-level done-signal for run_screening). topMatches is
the count worth scheduling.
Inputs: no named parameters.
parse_cvsA
Extract candidate identity (name, email, phone) from CV/resume files (PDF or DOCX, up to 20 per call). Runs OCR fallback for image-based PDFs. Returns deduplicated candidate rows ready to pass to schedule_interview.
Each entry in 'files' must have:
- 'name': filename including extension
- 'bytes_base64': base64-encoded file contents
If role_id is provided, dedups against candidates already attached to
that role. Files exceeding 20 are rejected — batch across multiple calls.
After parsing, ALWAYS show the user the extracted name/email/phone for
each file before scheduling, then call schedule_interview with the
returned 'candidates' list.
Inputs: files (required), role_id.
reassign_candidateA
Move a candidate from their current role to a different one. Existing meetings cascade to the new role. Records the reassignment in reassignmentAuditLogs with the optional reason.
ASK BEFORE CALLING if either candidate_id or to_role_id is not
unambiguous from the user's message. Reassignment affects all the
candidate's open meetings — confirm before moving.
Inputs: to_role_id (required), candidate_id (required), reason.
reschedule_interviewA
Reschedule a meeting. Emails the candidate a new invite link.
ASK BEFORE CALLING if the meeting isn't unambiguously identified
by the user's message. Same rule as cancel_interview: a
rescheduled-wrong-meeting message is awkward to clean up.
Inputs: meeting_id (required).
run_screeningAIdempotent
Start CV-vs-JD scoring for a screening's candidates. ASYNC: this returns immediately with {"status": "queued"} and NO scores — the LLM scoring runs in the background.
To read results, poll get_screening_results(role_id) a few seconds later
(and again until candidates leave the 'not_screened' status). Do not
expect scores in this tool's response.
- Scoring is idempotent: candidates whose CV+JD are unchanged since the
last run are skipped. Pass force=True to re-score everything (e.g.
after you have not changed the JD but want a fresh pass).
- limit: optionally cap how many candidates get scored this run.
- Uses a cheap model; safe to run on a large roster.
Inputs: role_id (required), force, limit.
schedule_interviewA
Schedule AI-driven interviews. Creates meetings and sends invite emails.
ASK BEFORE CALLING — DO NOT PICK A ROLE ON YOUR OWN:
- A role is MANDATORY and now ENFORCED: if you pass neither role_id
nor a position, this tool schedules NOTHING and returns
{"status": "role_required", "existingRoles": [...]}. When you get
that, ask the user which role to use, suggesting the returned
existingRoles, and only call again once they pick one.
- If the user did not name a role AND did not give enough info to
create a new one (position + JD/skills), STOP and ask first.
- Wrong role = wrong invite goes out. Treat role selection as
mandatory clarifying input; never default.
DRY RUN FIRST IF YOU'RE AUTO-FILLING ANYTHING:
- If you are supplying any field the user did not explicitly state —
interview_type, position, job_description, evaluation_focus,
duration, language, required_skills, OR candidates extracted from
a paste/CV — CALL WITH dry_run=True FIRST.
- The response returns the normalized candidates + the role payload
that WOULD be created or used, including the evaluation focus
split. Persists nothing, sends no email, consumes no quota.
- Read it back to the user in chat as a brief "here's what I'd send"
summary (4–6 bullet lines covering candidates, role, interview
type, focus split, JD if auto-generated). Get explicit go-ahead.
- THEN call again with dry_run=False to actually send invites.
- Only skip dry_run when EVERY field came from the user verbatim
(e.g. they named the role, the interview type, and pasted clean
structured candidates with no extraction).
EVALUATION FOCUS HANDLING:
- If user didn't specify, leave evaluation_focus out — backend
reuses the existing role's stored split, or applies an
interview-type default for new roles (screening:
role-fit/comms/experience/motivation; technical:
depth/problem-solving/comms/system-design; hr:
comms/culture/motivation/leadership).
- The dry-run response surfaces what the resolved split will be so
the user can override before invites go out.
CANDIDATE FIELDS:
- Each candidate dict requires 'firstName' and 'email'. Optional:
'lastName', 'phoneNumber', 'experience', 'summary'.
- Email must be well-formed; phone numbers auto-normalise to 10
digits (Indian format).
TIMING — IMPORTANT:
- This tool sends an invite EMAIL. The candidate opens the link
when they're ready; THEY pick the moment to start the interview.
You cannot pin an interview to a clock time via this tool.
- If a user says "schedule Priya for 3pm Tuesday" — explain that
AIIA invites are candidate-self-served, then offer to send the
invite now (so Priya has it in her inbox) or note the desired
window in the candidate summary so HR can chase if she hasn't
joined by then.
OTHER:
- interview_type: 'screening', 'technical', or 'hr'.
- duration: seconds per interview (default 900 = 15 min).
- language: 'en', 'hi', or 'ar'.
- If role_id is provided, position/jobDescription are ignored.
Returns per-candidate status. Some rows may succeed while others
fail (invalid email, quota exhausted, duplicate within role). Never
assume the whole batch succeeded.
Inputs: candidates (required), interview_type (required), dry_run, role_id, +9 more.
schedule_screened_candidatesADestructive
Schedule AI interviews for chosen candidates of a screening. Sends a real invite EMAIL to each and consumes interview quota.
CONFIRM BEFORE CALLING:
- Read back to the user which candidates (by name) you're about to invite
and get explicit go-ahead. This spends money and emails real people —
inviting the wrong candidates is not undoable in-band.
- Pull candidate_ids from get_screening_results 'id' fields. Only include
rows with hasEmail=true; rows with a placeholder email are REJECTED
(the whole call 400s) until a real email is added.
The interview reuses the screening role's stored config (JD, questions,
evaluation focus) — same as the web 'Schedule these N' action. The
candidate self-serves the interview when they open the link; you cannot
pin a clock time. duration is seconds per interview (default 900 = 15 min).
Returns {scheduledCount, scheduled_candidates:[{candidateId,
candidate_email, status ('scheduled'|'needs_email'|'skipped_existing'|
'failed'), meetingId, meetingUrl, reason}]}. Some rows may succeed while
others fail or are skipped (already scheduled) — never assume the whole
batch went out.
Inputs: role_id (required), candidate_ids (required), duration.
send_remindersAIdempotent
Send reminder emails for one or more pending interviews. Skips already-completed meetings. Pass the same idempotency_key on retry to avoid duplicate sends.
ASK BEFORE CALLING if the user said "remind everyone" / "the
no-shows" / anything that resolves to >1 meeting and you don't
have an explicit list. Call list_meetings (filter by status) first,
show the user the meetings you'd remind, and confirm before sending.
Reminder emails to the wrong candidates are an embarrassing leak.
Cap: 100 meeting_ids per call. For more, batch across multiple calls.
Inputs: meeting_ids (required), idempotency_key.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 18 tools
Tools have distinct purposes with detailed descriptions, but there is slight overlap between schedule_interview and schedule_screened_candidates (both schedule interviews, one for unscreened and one for screened candidates). Overall, the differences are clear from the descriptions.
All tool names follow a consistent verb_noun pattern in snake_case (e.g., list_meetings, create_screening_role, run_screening). No mixing of conventions like camelCase or irregular verbs.
With 18 tools, the set covers the full interview management lifecycle without being overwhelming. Each tool serves a specific function, and the count is appropriate for the domain.
The tool surface covers the screening pipeline (from role creation to scheduling screened candidates) and interview management (schedule, cancel, reschedule, list, get details, report, reminders). Minor gaps include no tool for updating candidate email or deleting roles, but core workflows are well-supported.
Maintenance
Related MCP Connectors
AI voice interviewer: create roles, screen CVs, schedule interviews, read scored reports.
Score resumes, screen candidates by phone, and check references from your AI assistant.
AI screening interviews, resume matching, and evidence-linked scorecards for recruiting teams.
Find your next great hire. Review candidates and manage hiring through your AI assistant.
Related MCP Servers
- AlicenseNot gradedqualityCmaintenanceThis MCP server provides hiring automation tools for recruitment processes. It enables users to generate job descriptions, score CVs, create interview questions, benchmark salaries, and draft offer letters through natural language interactions.16 npm31 PyPIMIT
- FlicenseAqualityDmaintenanceEnables interaction with IntelliMatch recruiting and iSuite insurance systems through spec-driven MCP tools, allowing natural language queries for candidate search, policy management, claims, and workflows.28-
- FlicenseNot gradedqualityFmaintenanceExposes HR recruitment actions as MCP tools over stdio, enabling AI clients to work with openings, candidates, interviews, and feedback through natural language.-
- AlicenseNot gradedqualityCmaintenanceEnables natural language management of job applications through MCP-compatible clients, including searching real job offers, creating and deleting applications, generating CVs or cover letters, and retrieving application metrics.ISC