Content
# Smile Dental MCP Server
MCP (Model Context Protocol) server for dental clinic appointment management. Provides tools for an AI receptionist to check availability and book appointments via **n8n workflows** connected to **Google Calendar** and **Gmail**.
## Architecture
```
AI Assistant (MCP Client)
│
│ stdio
▼
Dental MCP Server ──HTTP──► n8n Workflows ──► Google Calendar
│ + Gmail
│
└── Tools: check_availability, book_appointment
```
## Prerequisites
- Python 3.12+
- pip
- An n8n instance with the Smile Dental workflows deployed (check-availability + book-appointment webhooks)
## Setup
### 1. Install Dependencies
```bash
pip install -r requirements.txt
```
### 2. Configure Environment
Edit `.env` with your n8n webhook URLs and clinic settings:
```env
# n8n Webhook URLs (use ngrok URL if n8n is behind a tunnel)
N8N_CHECK_AVAILABILITY_URL=https://your-ngrok-url.ngrok-free.app/webhook/check-availability
N8N_BOOK_APPOINTMENT_URL=https://your-ngrok-url.ngrok-free.app/webhook/book-appointment
# Clinic Settings
CLINIC_NAME=Smile Dental Clinic
DEFAULT_TIMEZONE=America/Chicago
# API key for n8n authentication (must match what n8n expects)
N8N_API_KEY=smile-dental-demo-secret
# MCP Server API key (clients must send this as Bearer token in Authorization header)
# Generate a strong random key for production: python -c "import secrets; print(secrets.token_urlsafe(32))"
MCP_API_KEY=your-mcp-secret-key
```
## Run
```bash
python -m app.server
```
The server starts on **SSE transport** at `http://localhost:8000` and prints startup info:
```
🧑⚕️ Dental MCP Server starting...
Clinic: Smile Dental Clinic
Timezone: America/Chicago
Check Availability URL: https://.../webhook/check-availability
Book Appointment URL: https://.../webhook/book-appointment
Listening on http://0.0.0.0:8000/sse (SSE transport)...
```
## Authentication
The MCP server uses **Bearer token authentication** via the `Authorization` header.
1. Set a strong API key in `.env`:
```env
MCP_API_KEY=your-mcp-secret-key
```
Generate one with: `python -c "import secrets; print(secrets.token_urlsafe(32))"`
2. MCP clients must send the key as a Bearer token when connecting.
3. If `MCP_API_KEY` is empty or not set, authentication is **disabled** (not recommended for production).
## Expose as MCP Tool (SSE Transport)
Add this server to your MCP client configuration so your AI assistant can use the dental tools.
### Cursor
In Cursor settings → MCP Servers → Add:
- **Name:** `dental-mcp`
- **Type:** `sse`
- **URL:** `http://localhost:8000/sse`
- **Headers (optional):** Add `Authorization: Bearer your-mcp-secret-key`
### Other MCP Clients
Any MCP client that supports **SSE transport** can connect. The schema is:
```json
{
"mcpServers": {
"dental-mcp": {
"type": "sse",
"url": "http://localhost:8000/sse",
"headers": {
"Authorization": "Bearer your-mcp-secret-key"
}
}
}
}
```
## Available Tools
### 1. `check_availability`
Check available appointment slots for a given date and preferences.
| Parameter | Required | Default | Description |
|---|---|---|---|
| `appointmentType` | ✅ | — | Type of appointment (e.g., `Cleaning`, `New Patient Exam`, `Emergency`, `Follow-up Visit`, `Filling Consultation`, `Crown Consultation`, `Root Canal Consultation`) |
| `preferredDate` | ✅ | — | Date in `YYYY-MM-DD` format |
| `preferredTime` | ❌ | `Morning` | Time preference: `Morning`, `Afternoon`, `Evening`, or `Any` |
| `preferredProvider` | ❌ | `""` | Preferred dentist name (e.g., `Dr. Emily Carter`). Empty = no preference. |
| `patientType` | ❌ | `Existing` | `New` or `Existing` |
| `isEmergency` | ❌ | `false` | Whether this is an emergency |
**Returns:** Formatted list of up to 5 available time slots with provider info.
### 2. `book_appointment`
Book a new appointment for a patient. Sends confirmation email via Gmail.
| Parameter | Required | Default | Description |
|---|---|---|---|
| `firstName` | ✅ | — | Patient's first name |
| `lastName` | ✅ | — | Patient's last name |
| `phone` | ✅ | — | Patient's phone number |
| `appointmentType` | ✅ | — | Type of appointment (same values as above) |
| `appointmentDate` | ✅ | — | Date in `YYYY-MM-DD` format |
| `appointmentTime` | ✅ | — | Time (e.g., `10:30 AM`, `2:00 PM`) |
| `email` | ❌ | `""` | Patient's email (for confirmation) |
| `dateOfBirth` | ❌ | `""` | Date of birth `YYYY-MM-DD` |
| `patientType` | ❌ | `Existing` | `New` or `Existing` |
| `provider` | ❌ | `""` | Assigned provider/dentist |
| `hasInsurance` | ❌ | `false` | Whether patient has insurance |
| `insuranceProvider` | ❌ | `""` | Insurance provider name |
| `reasonForVisit` | ❌ | `""` | Reason for the visit |
| `additionalNotes` | ❌ | `""` | Any special requests |
**Returns:** Booking confirmation with appointment ID, date, time, and provider.
## Example MCP Tool Invocation (from AI Assistant)
```
User: "I need a cleaning appointment for next Friday."
AI Assistant (calls tool):
check_availability(
appointmentType="Cleaning",
preferredDate="2026-07-10",
preferredTime="Morning"
)
→ Shows available slots
User: "Book the first slot with Dr. Carter."
AI Assistant (calls tool):
book_appointment(
firstName="John",
lastName="Smith",
phone="5551234567",
email="john@email.com",
appointmentType="Cleaning",
appointmentDate="2026-07-10",
appointmentTime="9:00 AM",
provider="Dr. Emily Carter",
patientType="Existing"
)
→ Confirms booking + sends email
```
## Project Structure
```
dental-mcp/
├── .env # Configuration (webhook URLs, API key)
├── .gitignore # Git ignore rules
├── requirements.txt # Python dependencies
├── README.md # This file
└── app/
├── __init__.py
├── config.py # Settings loaded from .env
├── server.py # MCP server entry point
├── clients/
│ ├── __init__.py
│ └── n8n_client.py # HTTP client for n8n webhooks
├── schemas/
│ ├── __init__.py
│ ├── availability.py # Pydantic models for availability
│ └── booking.py # Pydantic models for booking
├── tools/
│ ├── __init__.py
│ ├── check_availability.py # check_availability tool
│ └── book_appointment.py # book_appointment tool
└── utils/
├── __init__.py
└── formatters.py # Response formatting helpers