Install
openclaw skills install @sprintcx/zoho-crm-mcpConnect your OpenClaw agent to Zoho CRM via MCP. Search contacts, list accounts, query records with COQL, and manage CRM data using mcporter. Includes ready-to-use Python scripts for common CRM operations.
openclaw skills install @sprintcx/zoho-crm-mcpConnect your OpenClaw agent to Zoho CRM through the Model Context Protocol (MCP). This skill provides everything you need to search, read, and manage CRM data using mcporter.
| Requirement | Details |
|---|---|
| Zoho CRM MCP Server | A configured endpoint from mcp.zoho.eu |
| mcporter | MCP client CLI (pre-installed with OpenClaw) |
| Environment variable | ZOHO_MCP_URL must be set (see below) |
This skill requires the ZOHO_MCP_URL environment variable. Without it, the Python scripts will not work.
Add this to your shell profile (e.g. ~/.bashrc or ~/.zshrc):
export ZOHO_MCP_URL="https://your-org-zoho-crm-xxxxx.zohomcp.eu/mcp/YOUR_TOKEN/message"
Or set it per session:
ZOHO_MCP_URL="https://your-org-zoho-crm-xxxxx.zohomcp.eu/mcp/YOUR_TOKEN/message" python3 scripts/list_contacts.py
To verify it's set:
echo $ZOHO_MCP_URL
https://your-org-zoho-crm-xxxxx.zohomcp.eu/mcp/abc123def456/message
ZOHO_MCP_URL as shown above.If you manage multiple Zoho CRM orgs, each gets its own MCP endpoint. You can:
ZOHO_MCP_URL.env file per projectmcporter list $ZOHO_MCP_URL
cat << 'EOF' > /tmp/zoho_search.json
{
"path_variables": {"module": "Contacts"},
"query_params": {"criteria": "(Last_Name:equals:Smith)"}
}
EOF
mcporter call "$ZOHO_MCP_URL.ZohoCRM_searchRecords" --args "$(< /tmp/zoho_search.json)"
cat << 'EOF' > /tmp/zoho_record.json
{
"path_variables": {"module": "Accounts", "recordID": "1234567890"}
}
EOF
mcporter call "$ZOHO_MCP_URL.ZohoCRM_getRecord" --args "$(< /tmp/zoho_record.json)"
cat << 'EOF' > /tmp/zoho_coql.json
{
"body": {"select_query": "SELECT Id, Account_Name, Website FROM Accounts WHERE Website != '' ORDER BY Account_Name LIMIT 50"}
}
EOF
mcporter call "$ZOHO_MCP_URL.ZohoCRM_executeCOQLQuery" --args "$(< /tmp/zoho_coql.json)"
Ready-to-use scripts for common CRM operations. All scripts require ZOHO_MCP_URL to be set.
# All contacts as table
python3 scripts/list_contacts.py
# Search by last name
python3 scripts/list_contacts.py --search "Smith"
# Raw JSON output
python3 scripts/list_contacts.py --json
# Full record data
python3 scripts/list_contacts.py --search "Smith" --json --full
# All accounts with website
python3 scripts/list_accounts.py
# Search by company name
python3 scripts/list_accounts.py --search "Acme"
# All accounts (including those without website)
python3 scripts/list_accounts.py --all
# JSON output
python3 scripts/list_accounts.py --json
# Search any module by name
python3 scripts/search_records.py Contacts "Smith"
python3 scripts/search_records.py Accounts "Acme Corp"
python3 scripts/search_records.py Deals "Project X"
# COQL query on any module
python3 scripts/search_records.py Contacts --coql "Email != ''" --json
Shell escaping breaks with inline JSON. Always write to a temp file:
cat << 'EOF' > /tmp/args.json
{
"path_variables": {"module": "Contacts"},
"query_params": {"criteria": "(Email:equals:test@example.com)"}
}
EOF
mcporter call "$ZOHO_MCP_URL.ZohoCRM_searchRecords" --args "$(< /tmp/args.json)"
For large result sets, use page and per_page:
{
"path_variables": {"module": "Contacts"},
"query_params": {"page": 2, "per_page": 200}
}
Get all field names for a module (useful before writing scripts or Deluge code):
cat << 'EOF' > /tmp/args.json
{
"query_params": {"module": "Contacts", "include": "allowed_permissions_to_update"}
}
EOF
mcporter call "$ZOHO_MCP_URL.ZohoCRM_getFields" --args "$(< /tmp/args.json)"
For a fully capable CRM agent, enable these actions on your Zoho MCP server at mcp.zoho.eu:
getModules - List all CRM modulesgetFields - Get field definitions for any modulegetRecord / getRecords - Read individual or lists of recordssearchRecords - Search by criteria (email, name, etc.)executeCOQLQuery - SQL-like queries across modulesgetRecordCount - Count records per modulegetRelatedRecords - Read linked records (e.g., contacts of an account)getPickListValues - Get dropdown options for fieldscreateRecords - Create new records in any moduleupdateRecord - Update a single record by IDupsertRecords - Insert or update (upsert)createNotes - Add notes to recordscreateEventsRecords - Create calendar eventscreateTags / postRemoveTags - Manage tagsdeleteRecord / deleteRecords - Only enable when specifically neededCOQL (Zoho's SQL-like query language) differs from standard SQL in several ways:
WHERE Last_Name = 'Smith'2026-01-01T00:00:00+01:00LIMIT 20 OFFSET 0true / false (lowercase)-- All contacts with email
SELECT Id, Full_Name, Email FROM Contacts WHERE Email != '' LIMIT 100
-- Deals from last 3 months
SELECT Id, Deal_Name, Amount, Stage FROM Deals WHERE Created_Time >= '2026-04-01T00:00:00+01:00'
-- Accounts by city
SELECT Id, Account_Name, Billing_City FROM Accounts WHERE Billing_City = 'Berlin'
Set the environment variable with your MCP endpoint URL. See "Environment Variable Setup" above.
Use the temp-file approach with --args "$(< /tmp/args.json)" instead of inline JSON.
The MCP connection token may have expired. Go to mcp.zoho.eu, revoke and reconnect the affected app to get a fresh token.
Zoho CRM shows display labels in the UI, but the API uses api_name values (e.g., Account_Name not "Account Name"). Always check field names with getFields before writing scripts or Deluge code.