GoHighLevel MCP Server
by traynewreck
README.md
# GoHighLevel MCP Server (Self-Hosted)
Use case: Connect AI apps like [RetellAI](https://dashboard.retellai.com/?ref=justin) and [Vapi](https://vapi.ai/?aff=justin6q) directly to [GoHighLevel (GHL)](https://www.gohighlevel.com/?fp_ref=lead-brain-llc81) for contact + booking workflows.
This project may also work with other MCP-compatible apps.
**No middleware required: direct RetellAI/Vapi -> GHL integration without apps like n8n or make.com.**
If this is your first time using [Vercel](https://vercel.com) or MCP, setup typically takes **15-30 minutes**.
You maybe asking why not just use GHL's native MCP? At the time of development they do not provide tooling for querying calendars for open slots or booking appointments.
## Table of Contents
- [What This Server Does](#what-this-server-does)
- [Quick Start Checklist](#quick-start-checklist)
- [1. Deploy on Vercel](#1-deploy-on-vercel)
- [2. Connect MCP in Your Agent Platform](#2-connect-mcp-in-your-agent-platform)
- [3. Recommended Agent Flow](#3-recommended-agent-flow)
- [4. Troubleshooting](#4-troubleshooting)
## What This Server Does
- Create or update contacts (`ghl_create_contact`)
- Search contacts (`ghl_search_contacts`)
- Retrieve calendar free slots (`ghl_get_calendar_free_slots`)
- Create confirmed appointments (`ghl_create_appointment`)
Endpoint:
- `POST /mcp`
## Quick Start Checklist
- Deploy this repo to [Vercel](https://vercel.com)
- Add required environment variables
- Copy your Vercel `/mcp` URL
- Add MCP in RetellAI with required headers
- Add all 4 tools to your Retell agent
- Run one end-to-end test call
---
## 1. Deploy on [Vercel](https://vercel.com)
### 1.1 Import this repo
1. Go to [Vercel](https://vercel.com).
2. Create a new project.
3. Import this GitHub repository.
4. Deploy.
### 1.2 Add environment variables
In [Vercel](https://vercel.com) project settings, add the following:
| Variable | Required | What it is | How to get it |
| ------------------------------- | -------- | ----------------------------------------------------------- | --------------------------------------------------------------------------------- |
| `GHL_PRIVATE_INTEGRATION_TOKEN` | Yes | GHL API token used by this MCP | GHL -> Settings -> Private Integrations -> create integration -> copy token |
| `DEFAULT_LOCATION_ID` | Yes | Sub-account location ID this server is scoped to | GHL sub-account -> Settings -> Business Information |
| `MCP_SHARED_SECRET` | Yes | Shared secret that authenticates MCP clients to your server | Choose your own secret (like a password) or generate with `openssl rand -hex 32` |
| `DEFAULT_TIMEZONE` | No | Default timezone fallback | Optional, default is `America/New_York` |
| `ALLOWED_LOCATION_IDS` | No | Optional multi-tenant allowlist | Comma-separated list of location IDs |
Private Integration scopes required:
- `contacts.readonly`
- `contacts.write`
- `calendars.readonly`
- `calendars/events.write`
Hardcoded in app (no env needed):
- GHL base URL: `https://services.leadconnectorhq.com`
- GHL API version header: `2021-07-28`
### 1.3 Confirm endpoint
Your MCP URL will be:
- `https://<your-vercel-domain>/mcp`
## 2. Connect MCP in Your Agent Platform
Choose one platform below. RetellAI and Vapi are separate alternatives.
This MCP server may also work with other MCP-capable platforms, but testing for this project was conducted using RetellAI and Vapi.
### Option A: RetellAI
### 2.1 Add MCP (matches Retell UI)
In RetellAI -> **Add MCP**:
- **Name**: `GHL MCP` (or any label)
- **URL**: `https://<your-vercel-domain>/mcp`
- **Timeout (ms)**: `10000`
Under **Headers**, add:
- `Authorization` = `Bearer <GHL_PRIVATE_INTEGRATION_TOKEN>`
- `locationId` = `<DEFAULT_LOCATION_ID>`
- `X-MCP-KEY` = `<MCP_SHARED_SECRET>`
- `calendarId` = `<GHL_CALENDAR_ID>`
Under **Query Parameters**:
- leave empty
Then click **Save**.
### 2.2 Add tools to your agent
In RetellAI -> **Add Tool**, add:
1. `ghl_create_contact`
2. `ghl_search_contacts`
3. `ghl_get_calendar_free_slots`
4. `ghl_create_appointment`
Recommended toggles:
- **Speak During Execution**: off
- **Speak After Execution**: on
Optional variable mapping:
- Store `ghl_create_contact.contactId` as `contact_id`
- Use `contact_id` for `ghl_create_appointment.contactId`
Important notes:
- `calendarId` header is required for calendar tools.
- `X-MCP-KEY` must exactly match your Vercel `MCP_SHARED_SECRET`.
- Get `calendarId` from GHL calendar settings.
---
### Option B: Vapi
### 2.3 Create the MCP tool
In Vapi:
1. Go to **Tools** (left menu).
2. Click **Create Tool**.
3. Select **MCP**.
Configure these fields:
- **Tool Name**: `ghl_mcp` (or any label)
- **Description**: `GHL MCP`
- **Server URL**: `https://<your-vercel-domain>/mcp`
- **Timeout**: `20` seconds (recommended)
Under **HTTP Headers**, add:
- `Authorization` = `Bearer <GHL_PRIVATE_INTEGRATION_TOKEN>`
- `locationId` = `<DEFAULT_LOCATION_ID>`
- `X-MCP-KEY` = `<MCP_SHARED_SECRET>`
- `calendarId` = `<GHL_CALENDAR_ID>`
Under **MCP Settings**:
- Select **Streamable HTTP (SHTTP)** (recommended)
- SSE is also supported if needed
Then click **Save**.
### 2.4 Assign the MCP tool to your assistant
After saving the MCP tool:
1. Go to **Assistants**.
2. Select your assistant.
3. Open the **Tools** dropdown/menu.
4. Assign the MCP tool you created.
Important:
- If the tool is not assigned to the assistant, calls will not use this MCP server.
- `X-MCP-KEY` must match your Vercel `MCP_SHARED_SECRET` exactly.
- `calendarId` header is required for calendar tools.
---
## 3. Recommended Agent Flow
1. `ghl_search_contacts`
2. `ghl_create_contact` (only if no match)
3. `ghl_get_calendar_free_slots`
4. `ghl_create_appointment`
### Copy/Paste system prompt tool policy
Use this in your Retell system prompt. You can customize it, but test with real calls before production.
```txt
Use MCP tools for all contact + booking actions.
Do not invent contact IDs, availability, or confirmations.
Never mention tool names, tool calls, or internal MCP/tool errors to the caller.
Flow:
1) Run ghl_search_contacts first using available phone/email/query.
2) If exactly one contact is found, use that contactId.
3) If no contact is found, collect missing phone/email and run ghl_create_contact.
4) If multiple contacts are found, disambiguate before booking.
5) Run ghl_get_calendar_free_slots and only offer returned slots.
6) Run ghl_create_appointment only with a confirmed contactId and an offered slot.
If no slots, ask for a different date range.
If tool error, say there is a technical issue and retry or escalate.
Confirm booking only after ghl_create_appointment succeeds.
```
---
## 4. Troubleshooting
- `401 AUTH_ERROR`: a required header is missing or invalid.
- `403` location access error: verify token access and `locationId`.
- Empty free slots:
- verify `calendarId` header
- verify date range + timezone
- verify calendar availability in GHL
This server cannot be deployed
Maintenance
ActivityInactive
ResponsivenessNo issues