Skip to main content
What You’ll Build: An intelligent interview coordinator that automatically schedules interviews, sends confirmation emails to candidates, notifies your interview panel, and handles all follow-up communications.

Introduction

Coordinating interviews involves juggling multiple calendars, sending professional emails, and ensuring everyone has the right information at the right time. This tutorial shows you how to build an AI-powered interview coordinator that handles all of this automatically. The bot will:
  • Check calendar availability (using the authenticated user’s calendar)
  • Create calendar events with multiple attendees
  • Send professional confirmation emails to candidates
  • Notify interview panel members with prep materials
  • Request feedback from interviewers after completion
By the end of this tutorial, you’ll have a working interview coordinator that can handle the entire scheduling and communication workflow with natural language commands.
What You’ll Learn:
  • Deploying Google Calendar and Gmail MCP servers
  • Setting up OAuth for multiple Google services
  • Creating an AI agent that coordinates between multiple tools
  • Sending professional, AI-generated emails
  • Managing complex multi-step workflows with Claude

Prerequisites

Before starting, make sure you have:
  • Metorial Account: Sign up and get your API key
  • Google Workspace Account: With Calendar and Gmail access
  • Anthropic API Key: Get one from Anthropic Console
  • Development Environment: Node.js 18+ or Python 3.9+

Architecture Overview

Here’s how the interview coordinator works:
  1. User provides interview details (candidate, role, date preferences, interviewers)
  2. AI checks calendar availability using Google Calendar MCP server (checks the authenticated user’s calendar)
  3. AI creates calendar event and adds interviewers as attendees
  4. AI sends confirmation email to candidate via Gmail
  5. AI sends prep email to interview panel via Gmail
Tools used: Google Calendar MCP Server (scheduling) + Gmail MCP Server (communications) + AI Model (coordination) The AI autonomously decides which tools to use and in what order, handling complex multi-step workflows without explicit programming.

Step 1: Deploy Google Calendar MCP Server

First, deploy the Google Calendar server from the Metorial catalog:
1

Navigate to Server Catalog

2

Find Google Calendar Server

Search for “Google Calendar” in the catalog
3

Deploy the Server

Click Deploy and note your deployment ID (starts with svd_)
Save your Calendar deployment ID - you’ll need it in Step 3. It looks like: svd_abc123def456Note on Multiple Interviewers: This deployment accesses one Google Calendar (the authenticated user’s calendar). To check availability across multiple interviewers’ calendars, each interviewer would need their own Calendar MCP deployment and OAuth session. For simplicity, this tutorial uses a single calendar instance.

Step 1b: Deploy Gmail MCP Server

Next, deploy the Gmail server for email communications:
1

Search for Gmail Server

In the same catalog, search for “Gmail”
2

Deploy the Server

Click Deploy and note your Gmail deployment ID
You now have two MCP servers deployed. Both will run in the same session, allowing the AI to coordinate between scheduling and email tools seamlessly.

Step 2: Set Up OAuth Authentication

Both Calendar and Gmail require OAuth authentication to access your Google Workspace.
1

Install Dependencies

npm install metorial @metorial/anthropic @anthropic-ai/sdk
2

Create OAuth Setup Script

import { Metorial } from "metorial";

const metorial = new Metorial({
  apiKey: "YOUR_METORIAL_API_KEY",
});

async function setupOAuth() {
  // Calendar OAuth
  const calendarOAuth = await metorial.oauth.sessions.create({
    serverDeploymentId: "YOUR_CALENDAR_DEPLOYMENT_ID",
  });

  console.log("Authorize Calendar here:", calendarOAuth.url);
  console.log("Calendar OAuth Session ID:", calendarOAuth.id);

  // Wait for authorization
  await metorial.oauth.waitForCompletion([calendarOAuth]);
  console.log("✓ Calendar authorized!");

  // Gmail OAuth
  const gmailOAuth = await metorial.oauth.sessions.create({
    serverDeploymentId: "YOUR_GMAIL_DEPLOYMENT_ID",
  });

  console.log("\nAuthorize Gmail here:", gmailOAuth.url);
  console.log("Gmail OAuth Session ID:", gmailOAuth.id);

  // Wait for authorization
  await metorial.oauth.waitForCompletion([gmailOAuth]);
  console.log("✓ Gmail authorized!");

  console.log("\nSave these OAuth Session IDs for your bot:");
  console.log("Calendar:", calendarOAuth.id);
  console.log("Gmail:", gmailOAuth.id);
}

setupOAuth();
3

Authorize in Browser

Visit both URLs in your browser and complete the Google OAuth flow for Calendar and Gmail access. The script will wait for you to authorize before continuing.
4

Save OAuth Session IDs

The script outputs your OAuth session IDs (starting with soas_). Save these for use in Step 3.
OAuth Scopes: Calendar needs calendar.events and calendar.readonly. Gmail needs gmail.send and gmail.readonly. These are configured automatically by Metorial.

Step 3: Build the Interview Coordinator

Now let’s build the main coordinator that orchestrates interview scheduling and communications.
import { Metorial } from "metorial";
import { metorialAnthropic } from "@metorial/anthropic";
import Anthropic from "@anthropic-ai/sdk";

// Initialize clients
const metorial = new Metorial({
  apiKey: "YOUR_METORIAL_API_KEY",
});

const anthropic = new Anthropic({
  apiKey: "YOUR_ANTHROPIC_API_KEY",
});

// Server deployment credentials
const CALENDAR_DEPLOYMENT_ID = "CALENDAR_DEPLOYMENT_ID";
const CALENDAR_OAUTH_SESSION_ID = "CALENDAR_OAUTH_SESSION_ID";
const GMAIL_DEPLOYMENT_ID = "GMAIL_DEPLOYMENT_ID";
const GMAIL_OAUTH_SESSION_ID = "GMAIL_OAUTH_SESSION_ID";

interface InterviewRequest {
  candidateName: string;
  candidateEmail: string;
  role: string;
  interviewers: string[]; // Email addresses
  durationMinutes: number;
  preferredDates: string[]; // ISO format dates
  interviewType: "technical" | "behavioral" | "panel";
}

async function scheduleInterview(request: InterviewRequest) {
  console.log(`Scheduling ${request.interviewType} interview for ${request.candidateName}...`);

  await metorial.withProviderSession(
    metorialAnthropic,
    {
      serverDeployments: [
        {
          serverDeploymentId: CALENDAR_DEPLOYMENT_ID,
          oauthSessionId: CALENDAR_OAUTH_SESSION_ID,
        },
        {
          serverDeploymentId: GMAIL_DEPLOYMENT_ID,
          oauthSessionId: GMAIL_OAUTH_SESSION_ID,
        },
      ],
      streaming: false,
    },
    async ({ tools, callTools }) => {
      const messages: Anthropic.MessageParam[] = [
        {
          role: "user",
          content: `Schedule interview and send confirmations:

Candidate: ${request.candidateName} (${request.candidateEmail})
Role: ${request.role}
Interviewers: ${request.interviewers.join(", ")}
Duration: ${request.durationMinutes} minutes
Preferred dates: ${request.preferredDates.join(", ")}
Type: ${request.interviewType}

Steps to complete:
1. Check calendar availability for all interviewers on preferred dates
2. Create calendar event with:
   - Title: "${request.role} Interview - ${request.candidateName}"
   - Add all interviewers as attendees
3. Send confirmation email to candidate (${request.candidateEmail}) with:
   - Subject: "Interview Scheduled - ${request.role}"
   - Professional email including: interview date/time, what to prepare, who they'll meet
4. Send prep email to interviewers (${request.interviewers.join(", ")}) with:
   - Subject: "Interview Prep - ${request.candidateName}"
   - Candidate background, interview format, evaluation guidelines

CRITICAL: Only use actual calendar data. If no slots available, inform user. DO NOT create events without checking availability first.`,
        },
      ];

      let response = await anthropic.messages.create({
        model: "claude-sonnet-4-20250514",
        max_tokens: 8192,
        tools: tools,
        messages: messages,
      });

      // Agentic loop - let AI use tools autonomously
      while (response.stop_reason === "tool_use") {
        const toolUseBlocks = response.content.filter(
          (block): block is Anthropic.ToolUseBlock => block.type === "tool_use"
        );

        console.log(`AI using ${toolUseBlocks.length} tool(s)...`);

        const toolResults = await callTools(toolUseBlocks);

        messages.push({ role: "assistant", content: response.content });
        messages.push(toolResults);

        response = await anthropic.messages.create({
          model: "claude-sonnet-4-20250514",
          max_tokens: 8192,
          tools: tools,
          messages: messages,
        });
      }

      // Extract final response
      const finalText = response.content
        .filter((block): block is Anthropic.TextBlock => block.type === "text")
        .map((block) => block.text)
        .join("\n");

      console.log("Interview coordination complete:", finalText);
    }
  );
}

// Example usage
scheduleInterview({
  candidateName: "John Novak",
  candidateEmail: "john.novak@sample.com",
  role: "Senior Software Engineer",
  interviewers: [
    "user@yourCompany.com",  // Hiring manager
  ],
  durationMinutes: 45,
  preferredDates: [
    "2026-02-7T14:00:00Z",  // First preference
    "2026-02-7T5:00:00Z",  // Second preference
    "2026-02-7T15:00:00Z",  // Third preference
  ],
  interviewType: "technical",
});
Key Implementation Details:
  • Single Session: Both Calendar and Gmail servers run in one session, allowing the AI to seamlessly switch between scheduling and emailing tools
  • Agentic Workflow: The AI autonomously decides which tools to use and in what order - no explicit programming needed
  • Anti-Hallucination: The prompt explicitly instructs using only actual calendar data to prevent AI from making up availability
  • Professional Communications: AI generates context-appropriate emails for candidates and interviewers
Multiple Interviewer Calendars: The current implementation uses a single Google Calendar MCP server instance, which only accesses one Google Calendar (the calendar of the authenticated user). To check availability across multiple interviewers’ calendars, you would need to:
  • Deploy a separate Calendar MCP server instance for each interviewer
  • Set up OAuth for each interviewer’s calendar
  • Pass multiple calendar server deployments to the session
For now, this tutorial demonstrates scheduling with a single calendar owner who can view their own availability. The interviewers array is used for adding attendees to the calendar event and sending prep emails, but not for checking their individual calendar availability.

Email Templates

The AI automatically generates professional emails tailored to each recipient. Here are examples of what the coordinator sends:
Subject: Interview Scheduled - Senior Software EngineerBody:
Hi Sarah,

Great news! We've scheduled your interview for the Senior Software Engineer position.

Interview Details:
- Date: Tuesday, February 10, 2026
- Time: 2:00 PM - 3:00 PM EST
- Duration: 60 minutes
- Format: Technical Interview

You'll be meeting with:
- Alex Chen, Hiring Manager
- Jordan Smith, Technical Lead

What to Prepare:
- Please have your development environment ready for a live coding session
- We'll be discussing system design and your recent project experience
- Feel free to ask questions about our team and tech stack

If you need to reschedule, please let us know as soon as possible.

Looking forward to speaking with you!

Best regards,
Hiring Team
Subject: Interview Prep - Sarah JohnsonBody:
Hi Team,

You have an upcoming interview scheduled:

Candidate: Sarah Johnson
Position: Senior Software Engineer
Interview Type: Technical
Date: Tuesday, February 10, 2026 at 2:00 PM EST
Duration: 60 minutes

Interview Format:
- First 10 minutes: Introductions and company overview
- Next 35 minutes: Technical assessment (live coding + system design)
- Final 15 minutes: Candidate questions

Evaluation Focus:
- Problem-solving approach and code quality
- System design thinking
- Communication and collaboration style
- Cultural fit and team dynamics

Please review the candidate's background before the interview and come prepared with your assessment criteria.

If you need to reschedule, please notify the team immediately.

Thanks,
Recruiting Team

Step 4: Test the Coordinator

Let’s test the coordinator with a realistic scenario:
// Test scenario: Schedule technical interview
await scheduleInterview({
  candidateName: "Alex Rivera",
  candidateEmail: "alex.rivera@example.com",
  role: "Staff Frontend Engineer",
  interviewers: [
    "engineering.director@company.com",
    "senior.engineer@company.com",
    "product.manager@company.com",
  ],
  durationMinutes: 90,  // Panel interview
  preferredDates: [
    "2026-02-15T13:00:00Z",
    "2026-02-16T14:00:00Z",
    "2026-02-17T10:00:00Z",
  ],
  interviewType: "panel",
});
Expected Output:
Scheduling panel interview for Alex Rivera...
AI using 3 tool(s)...
AI using 2 tool(s)...
AI using 2 tool(s)...
Interview coordination complete: Successfully scheduled panel interview for Alex Rivera on February 15, 2026 at 1:00 PM EST. Calendar event created. Confirmation email sent to candidate and prep email sent to all 3 interviewers (Engineering Director, Senior Engineer, Product Manager).
The coordinator will:
  1. Check availability on the authenticated user’s calendar (not all 3 interviewers - see note below)
  2. Find the first available slot (Feb 15 at 1:00 PM)
  3. Create a 90-minute calendar event with all 3 interviewers as attendees
  4. Send confirmation email to Alex with interview details
  5. Send prep email to all interviewers with candidate info
Calendar Availability Limitation: This example checks only the authenticated user’s calendar availability. To check all 3 interviewers’ calendars, you would need to deploy a separate Calendar MCP instance for each interviewer with their OAuth credentials. The interviewers array is used for adding attendees to the event and sending emails, not for checking their individual availability.

Troubleshooting

Possible causes:
  • OAuth session expired or invalid
  • Calendar API not enabled in Google Workspace
  • Insufficient permissions (need calendar.events scope)
  • No availability found in provided date range
Solutions:
  • Re-run OAuth setup to refresh credentials
  • Verify Calendar API is enabled at Google Cloud Console
  • Check OAuth session has correct scopes in Metorial dashboard
  • Expand preferred date range or reduce number of required attendees
Possible causes:
  • OAuth session expired for Gmail
  • Gmail API not enabled
  • Insufficient permissions (need gmail.send scope)
  • Daily sending limit reached (500 emails/day for standard accounts)
Solutions:
  • Re-run OAuth setup for Gmail specifically
  • Enable Gmail API in Google Cloud Console
  • Verify OAuth session includes gmail.send scope
  • Check your Gmail sending quota at Google Workspace Admin
Possible causes:
  • Sending from unverified domain
  • Email content triggers spam filters
  • High volume of emails in short period
Solutions:
  • Set up SPF and DKIM records for your sending domain
  • Use professional, well-formatted email templates
  • Add delays between bulk sends
  • Test email content with spam checking tools
  • Whitelist your sending address with recipients
Issue: Calendar event created despite conflictsSolution: This is likely a prompt issue. Ensure your prompt includes:
CRITICAL: Only use actual calendar data. If no slots available, inform user.
DO NOT create events without checking availability first.
The anti-hallucination instruction forces the AI to actually check calendars before proceeding.
Issue: Extra or missing attendeesSolution: Be explicit in your prompt about who should attend:
Add ALL these interviewers as attendees: {interviewers.join(", ")}
Do not add anyone else as an attendee.
Also verify the email addresses are correct in your request object.
Issue: Need to verify availability across multiple interviewers’ calendarsCurrent Limitation: A single Google Calendar MCP server instance can only access one calendar (the authenticated user’s calendar).Solution: To check availability across multiple interviewers:
  1. Deploy a separate Calendar MCP server instance for each interviewer
  2. Set up individual OAuth sessions for each interviewer’s calendar
  3. Pass all calendar deployments to serverDeployments array in your session
  4. Update your prompt to check all calendar instances before scheduling
Example with multiple calendars:
serverDeployments: [
  { serverDeploymentId: CALENDAR_1_ID, oauthSessionId: OAUTH_1_ID },
  { serverDeploymentId: CALENDAR_2_ID, oauthSessionId: OAUTH_2_ID },
  { serverDeploymentId: GMAIL_DEPLOYMENT_ID, oauthSessionId: GMAIL_OAUTH_ID }
]
For this tutorial, we use a single calendar and add interviewers as attendees without checking their availability.

Advanced Customization

Email Personalization

Customize email templates based on role, interview type, or company culture:
const emailTemplates = {
  technical: "Include coding prep tips",
  behavioral: "Focus on company values",
  panel: "List all interviewers with bios"
};
Pass templates to your prompt for context-aware emails.

Multi-Stage Interviews

Coordinate complex interview pipelines:
async function scheduleInterviewPipeline(
  candidate: Candidate,
  stages: InterviewStage[]
) {
  for (const stage of stages) {
    await scheduleInterview({
      ...candidate,
      ...stage
    });
  }
}
Schedule phone screen, technical, and panel interviews in sequence.

Feedback Collection

Request and aggregate interviewer feedback:
async function collectFeedback(
  interviewId: string,
  interviewers: string[]
) {
  // Send feedback forms after interview
  // AI analyzes responses for hiring decision
}
Automate post-interview feedback workflow.

Calendar Preferences

Respect interviewer working hours and preferences:
const preferences = {
  "eng.dir@co.com": {
    hours: "9-17",
    timezone: "America/New_York"
  }
};
Include preferences in AI prompt for smarter scheduling.

Multi-Language Support

Send emails in candidate’s preferred language:
const request = {
  ...interviewDetails,
  candidateLanguage: "es" // Spanish
};
AI automatically generates emails in requested language.

Multi-Calendar Support

Check availability across multiple interviewers’ calendars:
// Deploy separate Calendar MCP for each interviewer
const INTERVIEWER_CALENDARS = [
  { deploymentId: "svd_eng_dir", oauthId: "soas_eng_dir" },
  { deploymentId: "svd_senior_eng", oauthId: "soas_senior" }
];
Each interviewer needs their own Calendar MCP instance with OAuth.

Production Considerations

Before deploying to production:

Error Handling

Add comprehensive error handling for common failures:
try {
  await scheduleInterview(request);
} catch (error) {
  if (error.message.includes("OAuth")) {
    // Refresh OAuth tokens
  } else if (error.message.includes("quota")) {
    // Handle rate limits
  } else {
    // Log and alert on-call team
  }
}

Monitoring and Logging

Track key metrics for reliability:
  • Interview scheduling success rate
  • Email delivery rate
  • Calendar availability check duration
  • AI tool call patterns
Use Metorial’s built-in monitoring to track these metrics.

Testing Strategy

Test edge cases before production:
  • All interviewers unavailable on all dates
  • Invalid email addresses
  • Time zone edge cases (DST transitions)
  • Calendar quota limits
  • Gmail sending limits

Privacy and Compliance

Ensure GDPR/CCPA compliance:
  • Get consent before sending emails
  • Don’t store candidate data longer than necessary
  • Encrypt sensitive information in transit and at rest

Scalability

For high-volume hiring:
  • Implement request queuing to avoid rate limits
  • Cache calendar availability queries
  • Batch similar operations
  • Use Metorial’s webhook support for async processing

What’s Next

Now that you have a working interview coordinator, explore more capabilities: