Skip to main content
Glama
dpkdhingra91

AI Interview Agents MCP Server

Server Configuration

Describes the environment variables required to run the server.

NameRequiredDescriptionDefault
AIIA_BACKEND_URLNoOptional override for the API base URL if using a custom deployment.
AIIA_FIREBASE_TOKENYesYour Firebase token for authentication. Obtain via 'aiia-mcp login' or set directly.

Capabilities

Features and capabilities supported by this server

CapabilityDetails
tools
{
  "listChanged": false
}
prompts
{
  "listChanged": false
}
resources
{
  "subscribe": false,
  "listChanged": false
}
experimental
{}

Tools

Functions exposed to the LLM to take actions

NameDescription
list_meetingsA

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.
    
list_rolesA

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, ...}]}.
    
get_meetingA

Full details of a single meeting including transcript and feedback.

    meeting_id accepts the UUID or the integer primary key.
    
get_reportA

Scored interview report: analysisSummary, strengths, weaknesses, recommendations, averagePercentage, nextSteps.

    Returns status=processing if the report hasn't generated yet.
    
get_pipelineA

Pipeline view (invited / scheduled / completed / no-show) for a role.

Use to answer 'how is the hiring going for this role'.

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.
    
cancel_interviewA

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.
    
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.
    
send_remindersA

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.
    
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.
    
generate_questionsA

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'.
    
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.
    
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.
    
list_screening_rolesA

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.
    
add_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).
    
run_screeningA

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.
    
get_screening_resultsA

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.
    
schedule_screened_candidatesA

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.
    

Prompts

Interactive templates invoked by user choice

NameDescription

No prompts

Resources

Contextual data attached and managed by the client

NameDescription

No resources

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/dpkdhingra91/aiia-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server