OpenAI MCP CRM Integration: HubSpot & Zoho Setup Guide
Transform your CRM workflows with OpenAI Model Context Protocol. Connect ChatGPT directly to HubSpot and Zoho for AI-powered customer insights, automated data entry, and intelligent workflow automation.
faster data entry with MCP
saved per user daily
average setup time
natural language queries
Key Takeaways
Imagine asking ChatGPT "What deals are closing this week?" and getting real-time data from your CRM. Or saying "Create a contact for the lead I just met" and having it instantly added to HubSpot with proper formatting and lead scoring. This is no longer science fiction—it's the reality of Model Context Protocol (MCP).
In October 2025, both HubSpot and Zoho launched official MCP servers, allowing AI assistants like ChatGPT to directly access and manipulate CRM data through natural language. This guide will show you exactly how to set it up and automate your CRM workflows.
What is Model Context Protocol?
Model Context Protocol is an open standard that enables AI assistants to securely connect to external systems. Think of it as a universal adapter that lets ChatGPT, Claude, and other AI tools access your business data in real-time.
MCP works across AI platforms—ChatGPT, Claude, Cursor, and more. One integration, multiple AI assistants.
OAuth 2.1 authentication, encrypted connections, and granular permissions protect your sensitive CRM data.
AI assistants query live CRM data, ensuring responses are always current and accurate.
MCP Server Setup
Deploy an MCP server that connects to your CRM API (HubSpot or Zoho)
ChatGPT Connection
Configure ChatGPT to communicate with your MCP server via HTTPS
Natural Language Queries
Ask ChatGPT questions about your CRM data in plain English
HHubSpot MCP Setup Guide
HubSpot's official MCP server (launched October 2025) provides read-only access to contacts, companies, deals, tickets, and more. Here's how to set it up in under 5 minutes.
Requirements
- ChatGPT Plus, Pro, or Team subscription ($20+/month)
- HubSpot account with API access
- Node.js 18+ or Python 3.10+ installed
- HTTPS endpoint (ngrok for development)
ZZoho CRM MCP Setup Guide
Zoho's MCP integration supports 300+ third-party apps and offers more extensive CRM operations than HubSpot. Here's the complete setup process.
import os
from mcp import Server, Tool
from zcrmsdk import ZCRMRestClient, ZCRMRecord
from zcrmsdk.exception import ZCRMException
# Initialize Zoho CRM SDK
ZCRMRestClient.initialize({
"client_id": os.getenv("ZOHO_CLIENT_ID"),
"client_secret": os.getenv("ZOHO_CLIENT_SECRET"),
"redirect_uri": os.getenv("ZOHO_REDIRECT_URI"),
"access_type": "offline",
"apiBaseUrl": "https://www.zohoapis.com",
"apiVersion": "v2"
})
# Create MCP server
server = Server("zoho-crm")
@server.tool("get_contacts")
async def get_contacts(query: str = None, limit: int = 100):
"""Fetch contacts from Zoho CRM with optional search query"""
try:
module = ZCRMRestClient.get_module("Contacts")
if query:
response = module.search_records(query, page=1, per_page=limit)
else:
response = module.get_records(page=1, per_page=limit)
contacts = []
for record in response.data:
contacts.append({
"id": record.entity_id,
"name": record.get_field_value("Full_Name"),
"email": record.get_field_value("Email"),
"company": record.get_field_value("Account_Name"),
"phone": record.get_field_value("Phone"),
"created_time": str(record.created_time)
})
return {"contacts": contacts, "count": len(contacts)}
except ZCRMException as e:
return {"error": str(e), "status": "failed"}
@server.tool("create_contact")
async def create_contact(
first_name: str,
last_name: str,
email: str,
company: str = None,
phone: str = None
):
"""Create a new contact in Zoho CRM"""
try:
record = ZCRMRecord.get_instance("Contacts")
record.set_field_value("First_Name", first_name)
record.set_field_value("Last_Name", last_name)
record.set_field_value("Email", email)
if company:
record.set_field_value("Account_Name", company)
if phone:
record.set_field_value("Phone", phone)
response = record.create()
return {
"id": response.data.entity_id,
"status": "success",
"message": f"Created contact: {first_name} {last_name}"
}
except ZCRMException as e:
return {"error": str(e), "status": "failed"}
@server.tool("get_deals")
async def get_deals(stage: str = None, limit: int = 100):
"""Fetch deals from Zoho CRM, optionally filtered by stage"""
try:
module = ZCRMRestClient.get_module("Deals")
if stage:
query = f"(Stage:equals:{stage})"
response = module.search_records(query, page=1, per_page=limit)
else:
response = module.get_records(page=1, per_page=limit)
deals = []
for record in response.data:
deals.append({
"id": record.entity_id,
"name": record.get_field_value("Deal_Name"),
"amount": record.get_field_value("Amount"),
"stage": record.get_field_value("Stage"),
"closing_date": str(record.get_field_value("Closing_Date")),
"owner": record.get_field_value("Owner").name
})
return {"deals": deals, "count": len(deals), "total_value": sum(d["amount"] or 0 for d in deals)}
except ZCRMException as e:
return {"error": str(e), "status": "failed"}
@server.tool("update_deal")
async def update_deal(deal_id: str, stage: str = None, amount: float = None):
"""Update a deal in Zoho CRM"""
try:
record = ZCRMRecord.get_instance("Deals", deal_id)
if stage:
record.set_field_value("Stage", stage)
if amount:
record.set_field_value("Amount", amount)
response = record.update()
return {
"id": response.data.entity_id,
"status": "success",
"message": "Deal updated successfully"
}
except ZCRMException as e:
return {"error": str(e), "status": "failed"}
# Start the server
if __name__ == "__main__":
server.run(host="0.0.0.0", port=3000)Environment Variables (.env)
ZOHO_CLIENT_ID=your_client_id
ZOHO_CLIENT_SECRET=your_client_secret
ZOHO_REDIRECT_URI=http://localhost:3000/callback
ZOHO_REFRESH_TOKEN=your_refresh_tokenStep 1: Create Zoho API Credentials
- 1. Go to Zoho CRM API Documentation and follow the registration guide
- 2. Visit the Zoho API Console
- 3. Click "Add Client" → Server-based
- 4. Set redirect URI:
http://localhost:3000/callback - 5. Copy Client ID and Client Secret
- 6. Generate refresh token using Zoho's OAuth authorization URL
ZohoCRM.modules.ALL, ZohoCRM.settings.ALL. These grant full read/write access to your CRM data.Real-World Automation Workflows
Now that your MCP server is running, here are powerful workflows you can automate through ChatGPT conversations.
ChatGPT Prompt:
"Find all contacts from tech companies created this week and research their LinkedIn profiles to add job titles and company sizes."
What Happens:
- • Queries CRM for new tech contacts
- • Enriches data via web research
- • Updates CRM fields automatically
- • Notifies sales team of hot leads
ChatGPT Prompt:
"Analyze all deals in negotiation stage. Which ones are stalled and what actions should we take?"
What Happens:
- • Retrieves all negotiation deals
- • Analyzes activity patterns
- • Identifies stalled opportunities
- • Suggests next actions per deal
ChatGPT Prompt:
"Tag all contacts from enterprise accounts with 'VIP' and assign them to the enterprise sales team."
What Happens:
- • Identifies enterprise accounts
- • Adds VIP tags to contacts
- • Reassigns to correct team
- • Creates follow-up tasks
Combine multiple operations into intelligent workflows:
Example: New Lead Processing
- 1. Lead Capture: "Create a contact for john@acmecorp.com who I just met at the trade show"
- 2. Enrichment: AI automatically researches company info and adds to CRM
- 3. Scoring: AI evaluates lead quality based on company size, industry, and recent activity
- 4. Assignment: Routes high-value leads to senior reps, others to SDRs
- 5. Follow-up: Creates tasks and schedules personalized email sequence
Security Best Practices
Your CRM contains sensitive customer data. Follow these security practices to protect it while using MCP integrations.
Use OAuth 2.1, Not API Keys
OAuth tokens expire and can be revoked. API keys are permanent and more vulnerable if leaked.
Implement Token Rotation
# Refresh token every 50 minutes
from datetime import datetime, timedelta
token_expiry = datetime.now() + timedelta(minutes=50)
if datetime.now() >= token_expiry:
new_token = refresh_oauth_token()
update_mcp_server_config(new_token)Restrict Permissions
Only grant the minimum required scopes. Don't use *.ALL in production.
Always Use HTTPS
ChatGPT requires HTTPS. Deploy behind a reverse proxy with TLS certificates.
IP Whitelisting
# nginx config
location /mcp {
allow 13.52.0.0/16; # ChatGPT IPs
allow 52.24.0.0/14;
deny all;
proxy_pass http://localhost:3000;
}Rate Limiting
Prevent abuse with request throttling: 100 requests/min per user.
import os
import jwt
from datetime import datetime, timedelta
from functools import wraps
from flask import Flask, request, jsonify
from flask_limiter import Limiter
from flask_limiter.util import get_remote_address
app = Flask(__name__)
# Rate limiting: 100 requests per minute
limiter = Limiter(
app=app,
key_func=get_remote_address,
default_limits=["100 per minute"]
)
# JWT authentication
SECRET_KEY = os.getenv("JWT_SECRET_KEY")
def require_auth(f):
@wraps(f)
def decorated(*args, **kwargs):
token = request.headers.get("Authorization")
if not token:
return jsonify({"error": "Missing authentication"}), 401
try:
# Verify JWT token
payload = jwt.decode(token, SECRET_KEY, algorithms=["HS256"])
# Check expiration
if datetime.utcnow() > datetime.fromtimestamp(payload["exp"]):
return jsonify({"error": "Token expired"}), 401
# Attach user info to request
request.user = payload
except jwt.InvalidTokenError:
return jsonify({"error": "Invalid token"}), 401
return f(*args, **kwargs)
return decorated
@app.route("/mcp", methods=["POST"])
@limiter.limit("100/minute")
@require_auth
def mcp_endpoint():
"""Secure MCP endpoint with auth and rate limiting"""
# Validate request source
allowed_ips = os.getenv("ALLOWED_IPS", "").split(",")
if request.remote_addr not in allowed_ips:
return jsonify({"error": "Unauthorized IP"}), 403
# Process MCP request
action = request.json.get("action")
params = request.json.get("params", {})
# Input validation
if not action or not isinstance(params, dict):
return jsonify({"error": "Invalid request format"}), 400
# Execute action with error handling
try:
result = execute_mcp_action(action, params)
return jsonify(result), 200
except Exception as e:
# Log error (don't expose internals)
app.logger.error(f"MCP error: {str(e)}")
return jsonify({"error": "Internal server error"}), 500
# Encryption for sensitive data
from cryptography.fernet import Fernet
def encrypt_sensitive_data(data: str) -> str:
"""Encrypt PII before storing/transmitting"""
key = os.getenv("ENCRYPTION_KEY").encode()
f = Fernet(key)
return f.encrypt(data.encode()).decode()
def decrypt_sensitive_data(encrypted: str) -> str:
"""Decrypt PII when needed"""
key = os.getenv("ENCRYPTION_KEY").encode()
f = Fernet(key)
return f.decrypt(encrypted.encode()).decode()Production Deployment Guide
Move from local development to a production-ready MCP server that's scalable, monitored, and secure.
# Install Vercel CLI
npm install -g vercel
# Create vercel.json
{
"version": 2,
"builds": [
{
"src": "server.py",
"use": "@vercel/python"
}
],
"routes": [
{
"src": "/mcp",
"dest": "server.py"
}
],
"env": {
"HUBSPOT_ACCESS_TOKEN": "@hubspot-token",
"ZOHO_CLIENT_ID": "@zoho-client-id"
}
}
# Deploy
vercel --prod
# Add secrets
vercel secrets add hubspot-token "your_token"
vercel secrets add zoho-client-id "your_id"import logging
from prometheus_client import Counter, Histogram, start_http_server
# Metrics
mcp_requests = Counter('mcp_requests_total', 'Total MCP requests', ['action', 'status'])
mcp_latency = Histogram('mcp_request_duration_seconds', 'MCP request latency')
# Logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler('/var/log/mcp-server.log'),
logging.StreamHandler()
]
)
@mcp_latency.time()
def execute_mcp_action(action, params):
logger = logging.getLogger(__name__)
try:
logger.info(f"Executing action: {action}")
result = process_action(action, params)
mcp_requests.labels(action=action, status='success').inc()
return result
except Exception as e:
logger.error(f"Action failed: {action} - {str(e)}")
mcp_requests.labels(action=action, status='error').inc()
raise
# Start Prometheus metrics endpoint
start_http_server(9090)Ready to Transform Your CRM Workflows?
Our team specializes in CRM automation and AI integrations. We'll help you implement MCP, design custom workflows, and optimize your sales processes.
60%
Faster Data Entry
3 Hours
Saved Per User Daily
5 Min
Setup Time
Free consultation • Custom workflow design • Implementation support • Training included
Frequently Asked Questions
Related Articles
Continue exploring CRM automation and AI integration with these related guides