Skip to main content
Glama
SkanderBS2024

Zoho CRM MCP Server

zoho_tools.py12.7 kB
import json import requests from typing import Dict, List, Any, Optional from .zoho_auth import ZohoAuth class ZohoTools: """Zoho CRM API tools for MCP server.""" def __init__(self): self.auth = ZohoAuth() self.api_base = f"{self.auth.api_domain}/crm/v2" def _make_request(self, method: str, endpoint: str, data: Optional[Dict] = None) -> Dict[str, Any]: """Make authenticated API request to Zoho CRM.""" try: print(f"Getting auth headers...") headers = self.auth.get_auth_headers() print(f"Auth headers obtained") url = f"{self.api_base}/{endpoint}" print(f"Making {method} request to: {url}") if method.upper() == "GET": response = requests.get(url, headers=headers, timeout=10) elif method.upper() == "POST": response = requests.post(url, headers=headers, json=data, timeout=10) elif method.upper() == "PUT": response = requests.put(url, headers=headers, json=data, timeout=10) else: return {"error": f"Unsupported HTTP method: {method}"} print(f"Response status: {response.status_code}") if response.status_code in [200, 201]: return response.json() else: return { "error": f"API request failed with status {response.status_code}", "details": response.text } except Exception as e: print(f"Exception in _make_request: {e}") return {"error": f"Request failed: {str(e)}"} def get_contact_by_email(self, email: str) -> Dict[str, Any]: """Get contact information by email address. Args: email: Email address to search for Returns: Dict containing contact information or error message """ print(f"Searching for contact with email: {email}") # Search contacts by email search_params = { "criteria": f"Email:equals:{email}" } result = self._make_request("GET", "Contacts/search", search_params) if "error" in result: return result data = result.get("data", []) if not data: return {"error": "Contact not found"} # Return the first matching contact contact = data[0] return { "id": contact.get("id"), "first_name": contact.get("First_Name"), "last_name": contact.get("Last_Name"), "email": contact.get("Email"), "phone": contact.get("Phone"), "account_name": contact.get("Account_Name", {}).get("name") if contact.get("Account_Name") else None, "created_time": contact.get("Created_Time"), "modified_time": contact.get("Modified_Time") } def create_contact(self, first_name: str, last_name: str, email: str, phone: str) -> Dict[str, Any]: """Create a new contact in Zoho CRM. Args: first_name: Contact's first name last_name: Contact's last name email: Contact's email address phone: Contact's phone number Returns: Dict containing created contact information or error message """ print(f"Creating contact: {first_name} {last_name} ({email})") contact_data = { "data": [{ "First_Name": first_name, "Last_Name": last_name, "Email": email, "Phone": phone }] } result = self._make_request("POST", "Contacts", contact_data) if "error" in result: return result data = result.get("data", []) if not data: return {"error": "Failed to create contact"} created_contact = data[0] if created_contact.get("status") == "success": return { "id": created_contact.get("details", {}).get("id"), "status": "success", "message": "Contact created successfully" } else: return { "error": "Failed to create contact", "details": created_contact } def get_deal_by_name(self, deal_name: str) -> Dict[str, Any]: """Get deal information by deal name. Args: deal_name: Name of the deal to search for Returns: Dict containing deal information or error message """ print(f"Searching for deal: {deal_name}") search_params = { "criteria": f"Deal_Name:equals:{deal_name}" } result = self._make_request("GET", "Deals/search", search_params) if "error" in result: return result data = result.get("data", []) if not data: return {"error": "Deal not found"} deal = data[0] return { "id": deal.get("id"), "deal_name": deal.get("Deal_Name"), "amount": deal.get("Amount"), "stage": deal.get("Stage"), "contact_name": deal.get("Contact_Name", {}).get("name") if deal.get("Contact_Name") else None, "account_name": deal.get("Account_Name", {}).get("name") if deal.get("Account_Name") else None, "closing_date": deal.get("Closing_Date"), "created_time": deal.get("Created_Time"), "modified_time": deal.get("Modified_Time") } def create_deal(self, deal_name: str, contact_id: str, stage: str, amount: float) -> Dict[str, Any]: """Create a new deal in Zoho CRM. Args: deal_name: Name of the deal contact_id: ID of the associated contact stage: Deal stage (e.g., 'Qualification', 'Proposal', 'Closed Won') amount: Deal amount Returns: Dict containing created deal information or error message """ print(f"Creating deal: {deal_name} (${amount})") deal_data = { "data": [{ "Deal_Name": deal_name, "Contact_Name": contact_id, "Stage": stage, "Amount": amount }] } result = self._make_request("POST", "Deals", deal_data) if "error" in result: return result data = result.get("data", []) if not data: return {"error": "Failed to create deal"} created_deal = data[0] if created_deal.get("status") == "success": return { "id": created_deal.get("details", {}).get("id"), "status": "success", "message": "Deal created successfully" } else: return { "error": "Failed to create deal", "details": created_deal } def update_contact(self, contact_id: str, field: str, value: str) -> Dict[str, Any]: """Update a specific field of a contact. Args: contact_id: ID of the contact to update field: Field name to update (e.g., 'Phone', 'Email', 'First_Name') value: New value for the field Returns: Dict containing update status or error message """ print(f"Updating contact {contact_id}: {field} = {value}") update_data = { "data": [{ "id": contact_id, field: value }] } result = self._make_request("PUT", "Contacts", update_data) if "error" in result: return result data = result.get("data", []) if not data: return {"error": "Failed to update contact"} updated_contact = data[0] if updated_contact.get("status") == "success": return { "status": "success", "message": f"Contact {field} updated successfully" } else: return { "error": "Failed to update contact", "details": updated_contact } def list_open_deals(self) -> List[Dict[str, Any]]: """List all open deals (not closed won/lost). Returns: List of open deals or error message """ print("Fetching open deals...") # Get deals that are not in closed stages search_params = { "criteria": "(Stage:not_equal:Closed Won)and(Stage:not_equal:Closed Lost)" } result = self._make_request("GET", "Deals/search", search_params) if "error" in result: return result data = result.get("data", []) open_deals = [] for deal in data: open_deals.append({ "id": deal.get("id"), "deal_name": deal.get("Deal_Name"), "amount": deal.get("Amount"), "stage": deal.get("Stage"), "contact_name": deal.get("Contact_Name", {}).get("name") if deal.get("Contact_Name") else None, "account_name": deal.get("Account_Name", {}).get("name") if deal.get("Account_Name") else None, "closing_date": deal.get("Closing_Date"), "created_time": deal.get("Created_Time") }) return open_deals def get_user_info(self) -> Dict[str, Any]: """Get current user information. Returns: Dict containing user information or error message """ try: print("Fetching user information...") print("Making API request to get user info...") result = self._make_request("GET", "users?type=CurrentUser") print(f"API response received: {result is not None}") if "error" in result: print(f"Error in API response: {result['error']}") return result users = result.get("users", []) if not users: print("No user data in response") return {"error": "User information not found"} print("User info retrieved successfully") user = users[0] return { "id": user.get("id"), "full_name": user.get("full_name"), "email": user.get("email"), "role": user.get("role", {}).get("name") if user.get("role") else None, "profile": user.get("profile", {}).get("name") if user.get("profile") else None, "status": user.get("status"), "time_zone": user.get("time_zone") } except Exception as e: print(f"Error getting user info: {e}") return {"error": f"Exception occurred: {str(e)}"} # Tool function wrappers for MCP def get_contact_by_email(email: str) -> Dict[str, Any]: """MCP tool: Get contact by email address.""" tools = ZohoTools() return tools.get_contact_by_email(email) def create_contact(first_name: str, last_name: str, email: str, phone: str) -> Dict[str, Any]: """MCP tool: Create a new contact.""" tools = ZohoTools() return tools.create_contact(first_name, last_name, email, phone) def get_deal_by_name(deal_name: str) -> Dict[str, Any]: """MCP tool: Get deal by name.""" tools = ZohoTools() return tools.get_deal_by_name(deal_name) def create_deal(deal_name: str, contact_id: str, stage: str, amount: float) -> Dict[str, Any]: """MCP tool: Create a new deal.""" tools = ZohoTools() return tools.create_deal(deal_name, contact_id, stage, amount) def update_contact(contact_id: str, field: str, value: str) -> Dict[str, Any]: """MCP tool: Update a contact field.""" tools = ZohoTools() return tools.update_contact(contact_id, field, value) def list_open_deals() -> List[Dict[str, Any]]: """MCP tool: List all open deals.""" tools = ZohoTools() return tools.list_open_deals() def get_user_info() -> Dict[str, Any]: """MCP tool: Get current user information.""" tools = ZohoTools() return tools.get_user_info()

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/SkanderBS2024/zoho-mcp'

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