Skip to main content
Glama
RohitashAery

GHL MCP Server

by RohitashAery

GHL MCP Server

A production-grade Model Context Protocol (MCP) server that wraps the GoHighLevel (GHL) API v2, enabling Claude and other MCP clients to interact with GHL CRM as structured tools — creating contacts, sending messages, managing pipelines, booking appointments, and more.


Overview

This server exposes 113 tools as MCP tools — 111 GHL API tools across 17 modules, plus 2 AI agent tools that chain multiple GHL operations autonomously.

Module

Tools

Description

Contacts

14

CRUD, search, tags, notes, tasks, upsert

Conversations

7

List threads, send SMS/email, get messages, mark read, reports

Opportunities

9

Pipeline management, stage moves, CRUD

Calendars

15

Calendars, calendar groups, slots, book/update/cancel appointments

Payments

11

Products, invoices, transactions, subscriptions

Workflows

3

List, enroll/remove contacts from automations

Forms & Surveys

4

List forms/surveys, get submissions

Users

5

CRUD team members

Locations

16

Sub-account management, custom values, custom fields, tags

Media

3

Upload, list, delete media library files

Links

5

Custom tracking link management

Blogs

5

Blog post management

Funnels

5

Funnel and funnel-page management

Snapshots

2

View cloneable account snapshots

Documents

4

List, send docs/templates

SaaS

3

Plans, subscriptions, enable SaaS mode

AI Agents

2

Multi-step sales automation with LLM reasoning and HITL approval

Webhooks

inbound

Signature-validated event router


Related MCP server: ghl-mcp

Prerequisites

  • Python 3.11+

  • A GoHighLevel account with API access

  • (For OAuth) A GHL Marketplace app with OAuth credentials


Installation

# 1. Clone the repository
git clone https://github.com/RohitashAery/ghl-mcp-server.git
cd ghl-mcp-server

# 2. Copy and configure environment
cp .env.example .env
# Edit .env with your credentials (see configuration section below)

# 3. Install dependencies
pip install -e .

# 4. Create data directory for OAuth token storage
mkdir -p data

# 5. Start the server
python main.py

The server starts at http://localhost:8000. Visit http://localhost:8000/docs for the Swagger UI.


Configuration

All configuration is via environment variables (or .env file):

Variable

Default

Description

GHL_AUTH_MODE

private

Auth mode: private or oauth

GHL_PRIVATE_TOKEN

Private integration token (private mode)

GHL_LOCATION_ID

Default sub-account location ID

GHL_CLIENT_ID

OAuth app client ID

GHL_CLIENT_SECRET

OAuth app client secret

GHL_REDIRECT_URI

http://localhost:8000/oauth/callback

OAuth callback URL

MCP_TRANSPORT

http

Transport: http or stdio

HOST

0.0.0.0

HTTP server bind host

PORT

8000

HTTP server port

GHL_WEBHOOK_SECRET

HMAC secret for webhook validation

LOG_LEVEL

INFO

DEBUG, INFO, WARNING, ERROR

LOG_FORMAT

json

json (production) or console (development)

DB_PATH

./data/tokens.db

SQLite path for OAuth tokens

ALLOWED_MODULES

all

Comma-separated module names to expose, or all. Used for plan gating in hosted SaaS.

ALLOWED_API_KEYS

(empty)

Comma-separated API keys required on /mcp/sse. Empty disables the check. Used for Claude seat enforcement.

LLM_PROVIDER

anthropic

LLM backend for AI agents: anthropic or openai

ANTHROPIC_API_KEY

Anthropic API key (required if LLM_PROVIDER=anthropic)

OPENAI_API_KEY

OpenAI API key (required if LLM_PROVIDER=openai)

LLM_MODEL

claude-sonnet-4-6

Model name passed to the LLM provider

AGENT_CHECKPOINTER_DB

./data/agent_checkpoints.db

SQLite path for LangGraph HITL checkpoint state

CHROMA_PERSIST_DIR

./data/chroma

ChromaDB persistence directory for semantic vector search (Phase 2)


SaaS Hosting (Multi-client)

This server supports running as a managed hosted service with multiple clients on shared infrastructure. Each client gets an isolated container with their own credentials and plan-gated tool set.

Plan gating

Set ALLOWED_MODULES to a comma-separated list of module names:

# Tier 1 — 48 tools
ALLOWED_MODULES=contacts,conversations,opportunities,pipelines,calendars,forms

# Tier 2 — 88 tools
ALLOWED_MODULES=contacts,conversations,opportunities,pipelines,calendars,payments,invoices,transactions,subscriptions,workflows,forms,surveys,users,media,links,blogs,funnels,documents

# Tier 3 — 113 tools (default: all GHL tools + AI agents)
ALLOWED_MODULES=all

Claude only sees the tools in the allowed modules — blocked modules are invisible.

Claude seat enforcement

Set ALLOWED_API_KEYS to a comma-separated list of bearer tokens:

ALLOWED_API_KEYS=key-abc123,key-xyz789

Clients include their key in Claude Desktop config:

{
  "mcpServers": {
    "ghl": {
      "type": "sse",
      "url": "https://client.yourdomain.com/mcp/sse",
      "headers": { "Authorization": "Bearer key-abc123" }
    }
  }
}

See docs/saas-deployment.md for the full per-tier setup guide and docs/aws-deployment.md for the AWS ECS infrastructure guide.


Private Token Setup

  1. Log into GoHighLevel

  2. Go to Settings → Integrations → Private Integrations

  3. Click Create New Integration

  4. Give it a name and select all required scopes

  5. Copy the generated token

  6. Set GHL_PRIVATE_TOKEN=<token> in your .env

  7. Set GHL_AUTH_MODE=private


OAuth Setup

Step 1: Create a GHL Marketplace App

  1. Go to GHL Marketplace

  2. Click + Create App

  3. Set the Redirect URI to your server's callback URL (e.g. https://your-server.com/oauth/callback)

  4. Under Scopes, select all scopes listed in .env.example

  5. Save — copy your Client ID and Client Secret

Step 2: Configure your server

GHL_AUTH_MODE=oauth
GHL_CLIENT_ID=your_client_id
GHL_CLIENT_SECRET=your_client_secret
GHL_REDIRECT_URI=http://localhost:8000/oauth/callback

Step 3: Authorize

  1. Start the server: python main.py

  2. Open http://localhost:8000/oauth/authorize in your browser

  3. Select the GHL location to authorize

  4. After approval, you're redirected to /oauth/callback

  5. Token is stored in SQLite — the server auto-refreshes before expiry


Claude Desktop Setup (stdio mode)

Set MCP_TRANSPORT=stdio in your .env, then add to your Claude Desktop config:

macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
Windows: %APPDATA%\Claude\claude_desktop_config.json

{
  "mcpServers": {
    "ghl": {
      "command": "python",
      "args": ["/absolute/path/to/ghl-mcp-server/main.py"],
      "env": {
        "MCP_TRANSPORT": "stdio",
        "GHL_AUTH_MODE": "private",
        "GHL_PRIVATE_TOKEN": "your_token_here",
        "GHL_LOCATION_ID": "your_location_id",
        "LOG_FORMAT": "console"
      }
    }
  }
}

Restart Claude Desktop. The GHL tools will appear in the tools panel.


Claude.ai / N8N Setup (HTTP/SSE mode)

Set MCP_TRANSPORT=http and start the server. The SSE endpoint is:

http://your-server:8000/mcp/sse

Claude.ai connector: Add the SSE URL in Claude's connector settings.

N8N: Use the MCP Client node with the SSE endpoint URL.

Swagger UI: http://your-server:8000/docs


All Tools Reference

Contacts

Tool

Description

Required Params

ghl_contacts_create

Create a new contact

— (at least one of: email, phone)

ghl_contacts_get

Get contact by ID

contactId

ghl_contacts_search

Search contacts

ghl_contacts_update

Update contact fields

contactId, fields

ghl_contacts_delete

Delete a contact

contactId

ghl_contacts_add_tag

Add tags to contact

contactId, tags

ghl_contacts_remove_tag

Remove tags from contact

contactId, tags

ghl_contacts_add_note

Add a note

contactId, body

ghl_contacts_list_notes

List contact notes

contactId

ghl_contacts_add_task

Create a task

contactId, title, dueDate

ghl_contacts_list_tasks

List contact tasks

contactId

ghl_contacts_upsert

Create or update by email/phone

email or phone

Conversations

Tool

Description

Required Params

ghl_conversations_list

List conversation threads

ghl_conversations_get

Get a conversation

conversationId

ghl_conversations_send_sms

Send SMS to contact

contactId, message

ghl_conversations_send_email

Send email to contact

contactId, subject, body

ghl_conversations_get_messages

Get messages in thread

conversationId

ghl_conversations_mark_read

Mark conversation read

conversationId

Opportunities

Tool

Description

Required Params

ghl_opportunities_list

List opportunities

ghl_opportunities_get

Get opportunity

opportunityId

ghl_opportunities_create

Create opportunity

pipelineId, stageId, contactId, name

ghl_opportunities_update

Update opportunity

opportunityId, fields

ghl_opportunities_update_stage

Move to stage

opportunityId, stageId

ghl_opportunities_delete

Delete opportunity

opportunityId

ghl_pipelines_list

List all pipelines

Calendars & Appointments

Tool

Description

Required Params

ghl_calendars_list

List calendars

ghl_calendars_get_slots

Get available slots

calendarId, startDate, endDate

ghl_appointments_list

List appointments

ghl_appointments_create

Book appointment

calendarId, contactId, startTime, endTime

ghl_appointments_update

Update appointment

appointmentId, fields

ghl_appointments_cancel

Cancel appointment

appointmentId

Payments

Tool

Description

Required Params

ghl_payments_list_products

List products

ghl_invoices_create

Create invoice

contactId, items

ghl_invoices_list

List invoices

ghl_transactions_list

List transactions

ghl_subscriptions_list

List subscriptions

ghl_subscriptions_get

Get subscription

subscriptionId

Workflows

Tool

Description

Required Params

ghl_workflows_list

List workflows

ghl_workflows_add_contact

Enroll contact in workflow

workflowId, contactId

ghl_workflows_remove_contact

Remove from workflow

workflowId, contactId

Forms

Tool

Description

Required Params

ghl_forms_list

List forms

ghl_forms_get_submissions

Get form submissions

formId

Users

Tool

Description

Required Params

ghl_users_list

List team members

ghl_users_get

Get user by ID

userId

ghl_users_create

Create user

firstName, lastName, email

ghl_users_update

Update user

userId, fields

ghl_users_delete

Delete user

userId

Locations

Tool

Description

Required Params

ghl_locations_list

List sub-accounts

companyId

ghl_locations_get

Get location

locationId

ghl_locations_create

Create location

companyId, name

ghl_locations_update

Update location

locationId, fields

Documents

Tool

Description

Required Params

ghl_documents_list

List documents

ghl_documents_send

Send document

documentId, contactId

ghl_templates_list

List templates

ghl_templates_send

Send template

templateId, contactId

SaaS

Tool

Description

Required Params

ghl_saas_list_plans

List SaaS plans

companyId

ghl_saas_get_subscription

Get subscription status

ghl_saas_enable

Enable SaaS for location

planId

AI Agents

Multi-step autonomous agents powered by LangGraph. Each agent fetches data from multiple GHL domains, uses an LLM to reason about the best action, and executes it. High-stakes write actions (send SMS/email, move pipeline stage, enroll workflow) pause for human approval before executing.

Tool

Description

Required Params

ghl_agent_sales_automation

Run a full sales automation sequence for a contact: fetch contact + opportunities + conversations → LLM analysis → execute action (or pause for approval)

contact_id

ghl_agent_approve_action

Approve or reject a high-stakes action proposed by a suspended agent run

thread_id, approved

How the HITL (Human-in-the-Loop) flow works:

  1. Call ghl_agent_sales_automation(contact_id="abc123") — agent fetches data and reasons over it

  2. If the LLM proposes a high-stakes action (send SMS, move pipeline, etc.), it returns:

    { "status": "awaiting_approval", "thread_id": "uuid", "proposed_action": {...}, "reasoning": "..." }
  3. Review the proposed action, then call ghl_agent_approve_action(thread_id="uuid", approved=true) to execute it or approved=false to cancel

  4. For low-stakes actions (add note, add tag), the agent executes immediately and returns "status": "completed"

To resume a previously suspended run without re-running data fetching, pass thread_id to ghl_agent_sales_automation.

LLM setup: Set LLM_PROVIDER, ANTHROPIC_API_KEY (or OPENAI_API_KEY), and LLM_MODEL in your .env. The agent layer is model-agnostic — swap providers without changing any agent code.


Webhook Setup

  1. In GHL: go to Settings → Webhooks → Add Webhook

  2. Set the URL to https://your-server.com/webhooks/ghl

  3. Copy the Signing Secret from GHL and set GHL_WEBHOOK_SECRET=<secret> in .env

  4. Select the event types you want to receive

Supported Events

Event Type

Triggered When

ContactCreate

New contact created

ContactUpdate

Contact fields changed

ContactDelete

Contact deleted

OpportunityCreate

New opportunity created

OpportunityUpdate

Opportunity updated

OpportunityStatusChange

Opportunity won/lost/etc.

InboundMessage

Contact sent a message

OutboundMessage

Message sent to contact

AppointmentCreate

Appointment booked

AppointmentUpdate

Appointment changed

NoteCreate

Note added to contact

TaskCreate

Task added to contact

FormSubmission

Form submitted

PaymentSuccess

Payment completed

Custom Event Handlers

In mcp/webhooks.py, add your own logic:

from mcp.webhooks import webhook_handler

@webhook_handler("ContactCreate")
async def my_handler(event: dict) -> None:
    contact_id = event.get("id")
    # your custom logic here

Docker

# Build and start
docker-compose up -d

# View logs
docker-compose logs -f ghl-mcp-server

# Stop
docker-compose down

The data/ directory is mounted as a volume to persist OAuth tokens across restarts.


Running Tests

# Install dev dependencies
pip install -e ".[dev]"

# Run all tests with coverage
pytest

# Run specific module
pytest tests/test_contacts.py -v

# Run with HTML coverage report
pytest --cov-report=html
# Open htmlcov/index.html in browser

How to Add a New Tool

  1. Add the API method in api/<module>.py:

    async def my_new_action(self, location_id: str, param: str) -> dict[str, Any]:
        return await self._client.post("/endpoint", location_id=location_id, json={"param": param})
  2. Add the Pydantic model in models/<module>.py (if new response shape):

    class MyNewModel(BaseModel):
        id: str
        field: str
  3. Add the Tool definition in mcp/tools/<module>.py — append to the _<module>_tools() list:

    Tool(
        name="ghl_module_my_new_action",
        description="Clear description of what this does and when to use it.",
        inputSchema={
            "type": "object",
            "properties": {
                "locationId": {"type": "string"},
                "param": {"type": "string", "description": "What this param does"},
            },
            "required": ["param"],
        },
    ),
  4. Add the dispatch case in _dispatch() in the same file:

    elif name == "ghl_module_my_new_action":
        result = await api.my_new_action(location_id, arguments["param"])
  5. Write a test in tests/test_<module>.py:

    @pytest.mark.asyncio
    async def test_my_new_action(module_api, mock_ghl):
        mock_ghl.post("/endpoint").mock(return_value=httpx.Response(200, json={"ok": True}))
        result = await module_api.my_new_action("loc_id", "value")
        assert result["ok"] is True
  6. Register the tool — it's already wired up via mcp/server.py dispatch based on prefix.


Rate Limits

GHL enforces:

  • Burst limit: 100 requests per 10 seconds per location

  • Daily limit: ~200,000 requests per day

This server handles both automatically:

  • Token bucket per location: waits for refill if empty (never drops requests)

  • Daily warning: logs a warning at 80% of daily limit

  • Retry on 429: exponential backoff with jitter (up to 3 retries)

When the rate limit is hit, the tool call will wait (up to ~7 seconds across retries) rather than fail immediately.


Troubleshooting

Error

Cause

Fix

AuthenticationError: token invalid

GHL_PRIVATE_TOKEN is wrong or expired

Regenerate token in GHL Settings

ConfigurationError: locationId required

No locationId passed or GHL_LOCATION_ID not set

Set GHL_LOCATION_ID in .env or pass locationId in every tool call

NotFoundError

Resource ID doesn't exist in this location

Verify the ID belongs to the correct location

ValidationError (422)

Required GHL fields missing or wrong format

Check GHL API docs for required fields

GHLServerError (500/502/503)

GHL API is down

Server retries up to 3 times with backoff

OAuth: No token found for location

OAuth flow not completed

Visit /oauth/authorize and complete authorization

OAuth: Token refresh failed

Refresh token expired (>60 days unused)

Re-authorize via /oauth/authorize

Webhook: 401 Invalid signature

GHL_WEBHOOK_SECRET mismatch

Copy exact secret from GHL webhook settings

ImportError: mcp not found

MCP SDK not installed

Run pip install -e .

Agent: LLM_PROVIDER not set

AI agent tools called without LLM config

Set LLM_PROVIDER + ANTHROPIC_API_KEY or OPENAI_API_KEY in .env

Agent: No pending approval for thread

ghl_agent_approve_action called with stale ID

Restart with a new ghl_agent_sales_automation call

Agent: contact_id is required

Called ghl_agent_sales_automation without ID

Pass a valid GHL contact_id


Architecture

main.py               ← Entrypoint; starts stdio or HTTP transport
config.py             ← pydantic-settings; all env config
auth/
  private_token.py    ← Bearer token injection
  oauth.py            ← Auth code grant, token refresh, SQLite storage
api/
  client.py           ← httpx AsyncClient; retry, rate-limit, error mapping
  contacts.py         ← Raw GHL API calls (no business logic)
  ...
ghl_mcp/
  server.py           ← MCP Server; registers all 113 tools
  tools/
    contacts.py       ← Tool definitions + dispatch for contacts
    ...                 (17 domain tool files, all untouched by agent layer)
  agents/             ← LangGraph agent layer (NEW)
    base.py           ← GHLAgentContext, get_llm(), truncate_text()
    sales_automation.py ← LangGraph StateGraph: 7 nodes + HITL interrupt
    registry.py       ← MCP tool definitions + agent dispatch router
    checkpointer.py   ← MemorySaver singleton for HITL state persistence
    tools.py          ← LangChain StructuredTool wrappers (for future ReAct agents)
  webhooks.py         ← FastAPI router; signature validation + event routing
models/               ← Pydantic v2 models for GHL response shapes
tests/                ← pytest with respx mock for every module

Request flow — GHL tool (HTTP mode):

Claude → SSE /mcp/sse → MCP Server → tool dispatch → API module → GHLClient → GHL API v2

Request flow — AI agent tool:

Claude → SSE /mcp/sse → MCP Server → _agent_dispatch → LangGraph StateGraph
    → [fetch_contact] → [fetch_opportunities] → [fetch_conversations]
    → [analyze_and_plan (LLM)] → [request_approval (interrupt)] or [execute_action]
    → API module → GHLClient → GHL API v2

Agent HITL (Human-in-the-Loop) checkpoint flow:

ghl_agent_sales_automation  →  interrupt()  →  MemorySaver saves state
                                               → returns "awaiting_approval"
ghl_agent_approve_action    →  Command(resume=approved)  →  graph resumes
                                               → execute_action → completed
A
license - permissive license
-
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

  • A
    license
    B
    quality
    D
    maintenance
    A comprehensive MCP server that connects AI assistants to GoHighLevel CRM, enabling management of contacts, conversations, calendars, pipelines, payments, and more through 60+ tools.
    64
    27
    MIT
  • A
    license
    B
    quality
    D
    maintenance
    MCP server for GoHighLevel API v2 that provides 50+ tools for CRM, billing, marketing, and operations workflows, enabling natural language interaction with contacts, opportunities, conversations, and more.
    50
    1
    MIT
  • A
    license
    -
    quality
    C
    maintenance
    An MCP server for GoHighLevel with 82 live-tested tools, enabling CRM operations like contact management, appointments, invoices, and workflows via natural language.
    52
    MIT

View all related MCP servers

Related MCP Connectors

  • LeadConnector / GoHighLevel MCP Pack — wraps the GoHighLevel CRM for AI agents.

  • Hosted Amazon Seller Central and Amazon Ads MCP server for Claude, ChatGPT, Cursor, and agents.

  • Hosted Amazon Seller and Vendor MCP server for Claude, ChatGPT, Cursor, Codex, Gemini, Copilot.

View all MCP Connectors

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/RohitashAery/ghl-mcp-server'

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