Skip to main content
Glama
toolsets_recruiting.py60.3 kB
""" CATS MCP Server - Recruiting Toolsets Complete recruiting-focused toolsets for CATS API v3 """ from typing import Any, Optional from fastmcp import FastMCP # ============================================================================= # COMPANIES TOOLSET (18 tools) # ============================================================================= def register_companies_tools(mcp: FastMCP, make_request): """Register all companies-related tools""" # Main Company Operations @mcp.tool() async def list_companies(per_page: int = 25, page: int = 1) -> dict[str, Any]: """ List all companies with pagination. GET /companies Args: per_page: Number of companies per page (default: 25, max: 100) page: Page number for pagination (default: 1) Returns: List of companies with pagination metadata """ return await make_request("GET", "/companies", params={"per_page": per_page, "page": page}) @mcp.tool() async def get_company(company_id: int) -> dict[str, Any]: """ Get detailed information about a specific company. GET /companies/{id} Args: company_id: Unique identifier for the company Returns: Complete company details including contacts and jobs """ return await make_request("GET", f"/companies/{company_id}") @mcp.tool() async def create_company( name: str, website: Optional[str] = None, phone: Optional[str] = None, address: Optional[str] = None, city: Optional[str] = None, state: Optional[str] = None, zip_code: Optional[str] = None, notes: Optional[str] = None ) -> dict[str, Any]: """ Create a new company record. POST /companies Args: name: Company name (required) website: Company website URL phone: Company phone number address: Street address city: City state: State/province zip_code: ZIP or postal code notes: Additional notes about the company Returns: Created company details with ID """ payload = {"name": name} if website: payload["website"] = website if phone: payload["phone"] = phone if address: payload["address"] = address if city: payload["city"] = city if state: payload["state"] = state if zip_code: payload["zip_code"] = zip_code if notes: payload["notes"] = notes return await make_request("POST", "/companies", json_data=payload) @mcp.tool() async def update_company( company_id: int, name: Optional[str] = None, website: Optional[str] = None, phone: Optional[str] = None, address: Optional[str] = None, city: Optional[str] = None, state: Optional[str] = None, zip_code: Optional[str] = None, notes: Optional[str] = None ) -> dict[str, Any]: """ Update an existing company record. PUT /companies/{id} Args: company_id: ID of company to update name: Updated company name website: Updated website URL phone: Updated phone number address: Updated street address city: Updated city state: Updated state/province zip_code: Updated ZIP/postal code notes: Updated notes Returns: Updated company details """ payload = {} if name: payload["name"] = name if website: payload["website"] = website if phone: payload["phone"] = phone if address: payload["address"] = address if city: payload["city"] = city if state: payload["state"] = state if zip_code: payload["zip_code"] = zip_code if notes: payload["notes"] = notes return await make_request("PUT", f"/companies/{company_id}", json_data=payload) @mcp.tool() async def delete_company(company_id: int) -> dict[str, Any]: """ Delete a company record (permanent). DELETE /companies/{id} Args: company_id: ID of company to delete Returns: Deletion confirmation Warning: This is a permanent deletion. Consider archiving instead. """ return await make_request("DELETE", f"/companies/{company_id}") @mcp.tool() async def search_companies(query: str, per_page: int = 25) -> dict[str, Any]: """ Search companies by name or other criteria. GET /companies/search Args: query: Search query string per_page: Number of results per page (max: 100) Returns: List of matching companies """ return await make_request("GET", "/companies/search", params={"q": query, "per_page": per_page}) @mcp.tool() async def filter_companies( filters: dict[str, Any], per_page: int = 25, page: int = 1 ) -> dict[str, Any]: """ Filter companies using advanced criteria. POST /companies/search Args: filters: Dictionary of filter criteria (e.g., {"city": "San Francisco", "state": "CA"}) per_page: Results per page (max: 100) page: Page number Returns: Filtered list of companies """ payload = {**filters, "per_page": per_page, "page": page} return await make_request("POST", "/companies/search", json_data=payload) # Company Sub-Resources @mcp.tool() async def list_company_activities(company_id: int, per_page: int = 25, page: int = 1) -> dict[str, Any]: """ List all activities for a specific company. GET /companies/{id}/activities Args: company_id: Company ID per_page: Results per page page: Page number Returns: List of company activities """ return await make_request("GET", f"/companies/{company_id}/activities", params={"per_page": per_page, "page": page}) @mcp.tool() async def create_company_activity( company_id: int, activity_type: str, description: str, notes: Optional[str] = None ) -> dict[str, Any]: """ Create an activity for a company. POST /companies/{id}/activities Args: company_id: Company ID activity_type: Type (email, meeting, call_talked, call_lvm, call_missed, text_message, other) description: Activity description notes: Additional notes Returns: Created activity details """ payload = {"type": activity_type, "description": description} if notes: payload["notes"] = notes return await make_request("POST", f"/companies/{company_id}/activities", json_data=payload) @mcp.tool() async def list_company_attachments(company_id: int, per_page: int = 25, page: int = 1) -> dict[str, Any]: """ List all attachments for a company. GET /companies/{id}/attachments Args: company_id: Company ID per_page: Results per page page: Page number Returns: List of company attachments """ return await make_request("GET", f"/companies/{company_id}/attachments", params={"per_page": per_page, "page": page}) @mcp.tool() async def upload_company_attachment( company_id: int, file_data: dict[str, Any] ) -> dict[str, Any]: """ Upload an attachment to a company. POST /companies/{id}/attachments Args: company_id: Company ID file_data: File upload data (multipart/form-data) Returns: Created attachment details Note: File upload requires multipart/form-data handling """ return await make_request("POST", f"/companies/{company_id}/attachments", json_data=file_data) @mcp.tool() async def list_company_contacts(company_id: int, per_page: int = 25, page: int = 1) -> dict[str, Any]: """ List all contacts associated with a company. GET /companies/{id}/contacts Args: company_id: Company ID per_page: Results per page page: Page number Returns: List of company contacts """ return await make_request("GET", f"/companies/{company_id}/contacts", params={"per_page": per_page, "page": page}) @mcp.tool() async def get_company_custom_fields(company_id: int) -> dict[str, Any]: """ Get custom fields for a company. GET /companies/{id}/custom_fields Args: company_id: Company ID Returns: Company custom field values """ return await make_request("GET", f"/companies/{company_id}/custom_fields") @mcp.tool() async def list_company_departments(company_id: int) -> dict[str, Any]: """ List all departments within a company. GET /companies/{id}/departments Args: company_id: Company ID Returns: List of company departments """ return await make_request("GET", f"/companies/{company_id}/departments") @mcp.tool() async def create_company_department(company_id: int, name: str, description: Optional[str] = None) -> dict[str, Any]: """ Create a new department for a company. POST /companies/{id}/departments Args: company_id: Company ID name: Department name description: Department description Returns: Created department details """ payload = {"name": name} if description: payload["description"] = description return await make_request("POST", f"/companies/{company_id}/departments", json_data=payload) @mcp.tool() async def update_company_department( company_id: int, department_id: int, name: Optional[str] = None, description: Optional[str] = None ) -> dict[str, Any]: """ Update a company department. PUT /companies/{id}/departments/{dept_id} Args: company_id: Company ID department_id: Department ID name: Updated name description: Updated description Returns: Updated department details """ payload = {} if name: payload["name"] = name if description: payload["description"] = description return await make_request("PUT", f"/companies/{company_id}/departments/{department_id}", json_data=payload) @mcp.tool() async def delete_company_department(company_id: int, department_id: int) -> dict[str, Any]: """ Delete a company department. DELETE /companies/{id}/departments/{dept_id} Args: company_id: Company ID department_id: Department ID Returns: Deletion confirmation """ return await make_request("DELETE", f"/companies/{company_id}/departments/{department_id}") @mcp.tool() async def list_company_pipelines(company_id: int) -> dict[str, Any]: """ List all pipelines associated with a company. GET /companies/{id}/pipelines Args: company_id: Company ID Returns: List of company pipelines """ return await make_request("GET", f"/companies/{company_id}/pipelines") @mcp.tool() async def list_company_tags(company_id: int) -> dict[str, Any]: """ List all tags applied to a company. GET /companies/{id}/tags Args: company_id: Company ID Returns: List of company tags """ return await make_request("GET", f"/companies/{company_id}/tags") @mcp.tool() async def replace_company_tags(company_id: int, tag_ids: list[int]) -> dict[str, Any]: """ Replace all tags on a company (replaces existing tags). PUT /companies/{id}/tags Args: company_id: Company ID tag_ids: List of tag IDs to apply Returns: Updated tag list """ return await make_request("PUT", f"/companies/{company_id}/tags", json_data={"tag_ids": tag_ids}) @mcp.tool() async def attach_company_tags(company_id: int, tag_ids: list[int]) -> dict[str, Any]: """ Attach additional tags to a company (additive). POST /companies/{id}/tags Args: company_id: Company ID tag_ids: List of tag IDs to add Returns: Updated tag list """ return await make_request("POST", f"/companies/{company_id}/tags", json_data={"tag_ids": tag_ids}) @mcp.tool() async def delete_company_tags(company_id: int, tag_ids: list[int]) -> dict[str, Any]: """ Remove specific tags from a company. DELETE /companies/{id}/tags Args: company_id: Company ID tag_ids: List of tag IDs to remove Returns: Updated tag list """ return await make_request("DELETE", f"/companies/{company_id}/tags", json_data={"tag_ids": tag_ids}) # Company Phones @mcp.tool() async def list_company_phones(company_id: int, per_page: int = 25) -> dict[str, Any]: """ List all phone numbers for a company. GET /companies/{id}/phones Args: company_id: Company ID per_page: Results per page Returns: List of company phone numbers """ return await make_request("GET", f"/companies/{company_id}/phones", params={"per_page": per_page}) @mcp.tool() async def get_company_phone(phone_id: int) -> dict[str, Any]: """ Get a specific company phone. GET /phones/{id} Args: phone_id: Phone ID Returns: Phone details """ return await make_request("GET", f"/phones/{phone_id}") @mcp.tool() async def create_company_phone(company_id: int, phone: str, phone_type: str = "work") -> dict[str, Any]: """ Add a phone number for a company. POST /companies/{id}/phones Args: company_id: Company ID phone: Phone number phone_type: Type (work, mobile, etc.) Returns: Created phone object """ return await make_request("POST", f"/companies/{company_id}/phones", json_data={"phone": phone, "type": phone_type}) @mcp.tool() async def update_company_phone(phone_id: int, phone: Optional[str] = None, phone_type: Optional[str] = None) -> dict[str, Any]: """ Update a company phone number. PUT /phones/{id} Args: phone_id: Phone ID phone: Updated phone number phone_type: Updated type Returns: Updated phone object """ payload = {} if phone: payload["phone"] = phone if phone_type: payload["type"] = phone_type return await make_request("PUT", f"/phones/{phone_id}", json_data=payload) @mcp.tool() async def delete_company_phone(phone_id: int) -> dict[str, Any]: """ Delete a company phone number. DELETE /phones/{id} Args: phone_id: Phone ID Returns: Confirmation of deletion """ return await make_request("DELETE", f"/phones/{phone_id}") # Company Custom Fields Detail @mcp.tool() async def get_company_custom_field(company_id: int, field_id: int) -> dict[str, Any]: """ Get a specific custom field for a company. GET /companies/{id}/custom_fields/{field_id} Args: company_id: Company ID field_id: Custom field ID Returns: Custom field value """ return await make_request("GET", f"/companies/{company_id}/custom_fields/{field_id}") @mcp.tool() async def list_company_custom_field_values(company_id: int) -> dict[str, Any]: """ List all custom field values for a company. GET /companies/{id}/custom_field_values Args: company_id: Company ID Returns: List of custom field values """ return await make_request("GET", f"/companies/{company_id}/custom_field_values") @mcp.tool() async def get_company_custom_field_value(company_id: int, field_id: int) -> dict[str, Any]: """ Get a specific custom field value for a company. GET /companies/{id}/custom_field_values/{field_id} Args: company_id: Company ID field_id: Custom field ID Returns: Custom field value details """ return await make_request("GET", f"/companies/{company_id}/custom_field_values/{field_id}") # Company Statuses @mcp.tool() async def list_company_statuses() -> dict[str, Any]: """ List all available company statuses. GET /company_statuses Returns: List of company statuses """ return await make_request("GET", "/company_statuses") @mcp.tool() async def get_company_status(company_id: int) -> dict[str, Any]: """ Get the current status of a company. GET /companies/{id}/status Args: company_id: Company ID Returns: Current company status """ return await make_request("GET", f"/companies/{company_id}/status") @mcp.tool() async def change_company_status(company_id: int, status_id: int, reason: Optional[str] = None) -> dict[str, Any]: """ Change the status of a company. PUT /companies/{id}/status Args: company_id: Company ID status_id: New status ID reason: Optional reason for change Returns: Updated company with new status """ payload = {"status_id": status_id} if reason: payload["reason"] = reason return await make_request("PUT", f"/companies/{company_id}/status", json_data=payload) # Company Lists @mcp.tool() async def list_company_lists(per_page: int = 25, page: int = 1) -> dict[str, Any]: """ List all company lists. GET /company_lists Args: per_page: Results per page page: Page number Returns: List of company lists """ return await make_request("GET", "/company_lists", params={"per_page": per_page, "page": page}) @mcp.tool() async def get_company_list(list_id: int) -> dict[str, Any]: """ Get a specific company list. GET /company_lists/{id} Args: list_id: List ID Returns: Company list details """ return await make_request("GET", f"/company_lists/{list_id}") @mcp.tool() async def create_company_list(name: str, description: Optional[str] = None) -> dict[str, Any]: """ Create a new company list. POST /company_lists Args: name: List name description: List description Returns: Created company list """ payload = {"name": name} if description: payload["description"] = description return await make_request("POST", "/company_lists", json_data=payload) @mcp.tool() async def delete_company_list(list_id: int) -> dict[str, Any]: """ Delete a company list. DELETE /company_lists/{id} Args: list_id: List ID Returns: Confirmation of deletion """ return await make_request("DELETE", f"/company_lists/{list_id}") @mcp.tool() async def list_company_list_items(list_id: int, per_page: int = 25, page: int = 1) -> dict[str, Any]: """ List all items in a company list. GET /company_lists/{id}/items Args: list_id: List ID per_page: Results per page page: Page number Returns: List of company list items """ return await make_request("GET", f"/company_lists/{list_id}/items", params={"per_page": per_page, "page": page}) @mcp.tool() async def get_company_list_item(list_id: int, item_id: int) -> dict[str, Any]: """ Get a specific company list item. GET /company_lists/{list_id}/items/{item_id} Args: list_id: List ID item_id: Item ID Returns: Company list item details """ return await make_request("GET", f"/company_lists/{list_id}/items/{item_id}") @mcp.tool() async def create_company_list_items(list_id: int, company_ids: list[int]) -> dict[str, Any]: """ Add companies to a list. POST /company_lists/{id}/items Args: list_id: List ID company_ids: List of company IDs to add Returns: Created list items """ return await make_request("POST", f"/company_lists/{list_id}/items", json_data={"company_ids": company_ids}) @mcp.tool() async def delete_company_list_item(list_id: int, item_id: int) -> dict[str, Any]: """ Remove a company from a list. DELETE /company_lists/{list_id}/items/{item_id} Args: list_id: List ID item_id: Item ID Returns: Confirmation of deletion """ return await make_request("DELETE", f"/company_lists/{list_id}/items/{item_id}") # Company Departments @mcp.tool() async def list_departments(company_id: int, per_page: int = 25) -> dict[str, Any]: """ List all departments for a company. GET /companies/{id}/departments Args: company_id: Company ID per_page: Results per page Returns: List of departments """ return await make_request("GET", f"/companies/{company_id}/departments", params={"per_page": per_page}) @mcp.tool() async def get_department(department_id: int) -> dict[str, Any]: """ Get a specific department. GET /departments/{id} Args: department_id: Department ID Returns: Department details """ return await make_request("GET", f"/departments/{department_id}") @mcp.tool() async def add_department(company_id: int, name: str, description: Optional[str] = None) -> dict[str, Any]: """ Add a new department to a company. POST /companies/{id}/departments Args: company_id: Company ID name: Department name description: Department description Returns: Created department """ payload = {"name": name} if description: payload["description"] = description return await make_request("POST", f"/companies/{company_id}/departments", json_data=payload) @mcp.tool() async def update_department(department_id: int, name: Optional[str] = None, description: Optional[str] = None) -> dict[str, Any]: """ Update a department. PUT /departments/{id} Args: department_id: Department ID name: Updated name description: Updated description Returns: Updated department """ payload = {} if name: payload["name"] = name if description: payload["description"] = description return await make_request("PUT", f"/departments/{department_id}", json_data=payload) @mcp.tool() async def delete_department(department_id: int) -> dict[str, Any]: """ Delete a department. DELETE /departments/{id} Args: department_id: Department ID Returns: Confirmation of deletion """ return await make_request("DELETE", f"/departments/{department_id}") # Company Thumbnails @mcp.tool() async def get_company_thumbnail(company_id: int) -> dict[str, Any]: """ Get a company's thumbnail image. GET /companies/{id}/thumbnail Args: company_id: Company ID Returns: Thumbnail image data """ return await make_request("GET", f"/companies/{company_id}/thumbnail") @mcp.tool() async def change_company_thumbnail(company_id: int, image_data: str) -> dict[str, Any]: """ Update a company's thumbnail image. PUT /companies/{id}/thumbnail Args: company_id: Company ID image_data: Base64 encoded image data or image URL Returns: Updated thumbnail information """ return await make_request("PUT", f"/companies/{company_id}/thumbnail", json_data={"image": image_data}) # ============================================================================= # CONTACTS TOOLSET (18 tools) # ============================================================================= def register_contacts_tools(mcp: FastMCP, make_request): """Register all contacts-related tools""" # Main Contact Operations @mcp.tool() async def list_contacts(per_page: int = 25, page: int = 1) -> dict[str, Any]: """ List all contacts with pagination. GET /contacts Args: per_page: Number of contacts per page (default: 25, max: 100) page: Page number for pagination (default: 1) Returns: List of contacts with pagination metadata """ return await make_request("GET", "/contacts", params={"per_page": per_page, "page": page}) @mcp.tool() async def get_contact(contact_id: int) -> dict[str, Any]: """ Get detailed information about a specific contact. GET /contacts/{id} Args: contact_id: Unique identifier for the contact Returns: Complete contact details including company association """ return await make_request("GET", f"/contacts/{contact_id}") @mcp.tool() async def create_contact( first_name: str, last_name: str, email: str, company_id: Optional[int] = None, title: Optional[str] = None, phone: Optional[str] = None, notes: Optional[str] = None ) -> dict[str, Any]: """ Create a new contact record. POST /contacts Args: first_name: Contact's first name (required) last_name: Contact's last name (required) email: Contact's email address (required) company_id: Associated company ID title: Job title phone: Phone number notes: Additional notes Returns: Created contact details with ID """ payload = { "first_name": first_name, "last_name": last_name, "email": email } if company_id: payload["company_id"] = company_id if title: payload["title"] = title if phone: payload["phone"] = phone if notes: payload["notes"] = notes return await make_request("POST", "/contacts", json_data=payload) @mcp.tool() async def update_contact( contact_id: int, first_name: Optional[str] = None, last_name: Optional[str] = None, email: Optional[str] = None, company_id: Optional[int] = None, title: Optional[str] = None, phone: Optional[str] = None, notes: Optional[str] = None ) -> dict[str, Any]: """ Update an existing contact record. PUT /contacts/{id} Args: contact_id: ID of contact to update first_name: Updated first name last_name: Updated last name email: Updated email address company_id: Updated company association title: Updated job title phone: Updated phone number notes: Updated notes Returns: Updated contact details """ payload = {} if first_name: payload["first_name"] = first_name if last_name: payload["last_name"] = last_name if email: payload["email"] = email if company_id: payload["company_id"] = company_id if title: payload["title"] = title if phone: payload["phone"] = phone if notes: payload["notes"] = notes return await make_request("PUT", f"/contacts/{contact_id}", json_data=payload) @mcp.tool() async def delete_contact(contact_id: int) -> dict[str, Any]: """ Delete a contact record (permanent). DELETE /contacts/{id} Args: contact_id: ID of contact to delete Returns: Deletion confirmation Warning: This is a permanent deletion. """ return await make_request("DELETE", f"/contacts/{contact_id}") @mcp.tool() async def search_contacts(query: str, per_page: int = 25) -> dict[str, Any]: """ Search contacts by name, email, or other criteria. GET /contacts/search Args: query: Search query string per_page: Number of results per page (max: 100) Returns: List of matching contacts """ return await make_request("GET", "/contacts/search", params={"q": query, "per_page": per_page}) @mcp.tool() async def filter_contacts( filters: dict[str, Any], per_page: int = 25, page: int = 1 ) -> dict[str, Any]: """ Filter contacts using advanced criteria. POST /contacts/search Args: filters: Dictionary of filter criteria (e.g., {"company_id": 123, "title": "Manager"}) per_page: Results per page (max: 100) page: Page number Returns: Filtered list of contacts """ payload = {**filters, "per_page": per_page, "page": page} return await make_request("POST", "/contacts/search", json_data=payload) # Contact Sub-Resources @mcp.tool() async def list_contact_activities(contact_id: int, per_page: int = 25, page: int = 1) -> dict[str, Any]: """ List all activities for a specific contact. GET /contacts/{id}/activities Args: contact_id: Contact ID per_page: Results per page page: Page number Returns: List of contact activities """ return await make_request("GET", f"/contacts/{contact_id}/activities", params={"per_page": per_page, "page": page}) @mcp.tool() async def create_contact_activity( contact_id: int, activity_type: str, description: str, notes: Optional[str] = None ) -> dict[str, Any]: """ Create an activity for a contact. POST /contacts/{id}/activities Args: contact_id: Contact ID activity_type: Type (email, meeting, call_talked, call_lvm, call_missed, text_message, other) description: Activity description notes: Additional notes Returns: Created activity details """ payload = {"type": activity_type, "description": description} if notes: payload["notes"] = notes return await make_request("POST", f"/contacts/{contact_id}/activities", json_data=payload) @mcp.tool() async def list_contact_attachments(contact_id: int, per_page: int = 25, page: int = 1) -> dict[str, Any]: """ List all attachments for a contact. GET /contacts/{id}/attachments Args: contact_id: Contact ID per_page: Results per page page: Page number Returns: List of contact attachments """ return await make_request("GET", f"/contacts/{contact_id}/attachments", params={"per_page": per_page, "page": page}) @mcp.tool() async def upload_contact_attachment( contact_id: int, file_data: dict[str, Any] ) -> dict[str, Any]: """ Upload an attachment to a contact. POST /contacts/{id}/attachments Args: contact_id: Contact ID file_data: File upload data (multipart/form-data) Returns: Created attachment details Note: File upload requires multipart/form-data handling """ return await make_request("POST", f"/contacts/{contact_id}/attachments", json_data=file_data) @mcp.tool() async def get_contact_custom_fields(contact_id: int) -> dict[str, Any]: """ Get custom fields for a contact. GET /contacts/{id}/custom_fields Args: contact_id: Contact ID Returns: Contact custom field values """ return await make_request("GET", f"/contacts/{contact_id}/custom_fields") @mcp.tool() async def list_contact_emails(contact_id: int, per_page: int = 25, page: int = 1) -> dict[str, Any]: """ List all email addresses for a contact. GET /contacts/{id}/emails Args: contact_id: Contact ID per_page: Results per page page: Page number Returns: List of contact email addresses """ return await make_request("GET", f"/contacts/{contact_id}/emails", params={"per_page": per_page, "page": page}) @mcp.tool() async def create_contact_email(contact_id: int, email: str, email_type: str = "work") -> dict[str, Any]: """ Add an email address to a contact. POST /contacts/{id}/emails Args: contact_id: Contact ID email: Email address email_type: Type (work, personal, other) Returns: Created email details """ return await make_request("POST", f"/contacts/{contact_id}/emails", json_data={"email": email, "type": email_type}) @mcp.tool() async def update_contact_email(contact_id: int, email_id: int, email: str, email_type: str) -> dict[str, Any]: """ Update a contact's email address. PUT /contacts/{id}/emails/{email_id} Args: contact_id: Contact ID email_id: Email record ID email: Updated email address email_type: Updated type (work, personal, other) Returns: Updated email details """ return await make_request("PUT", f"/contacts/{contact_id}/emails/{email_id}", json_data={"email": email, "type": email_type}) @mcp.tool() async def delete_contact_email(contact_id: int, email_id: int) -> dict[str, Any]: """ Delete a contact's email address. DELETE /contacts/{id}/emails/{email_id} Args: contact_id: Contact ID email_id: Email record ID Returns: Deletion confirmation """ return await make_request("DELETE", f"/contacts/{contact_id}/emails/{email_id}") @mcp.tool() async def list_contact_phones(contact_id: int, per_page: int = 25, page: int = 1) -> dict[str, Any]: """ List all phone numbers for a contact. GET /contacts/{id}/phones Args: contact_id: Contact ID per_page: Results per page page: Page number Returns: List of contact phone numbers """ return await make_request("GET", f"/contacts/{contact_id}/phones", params={"per_page": per_page, "page": page}) @mcp.tool() async def create_contact_phone(contact_id: int, phone: str, phone_type: str = "work") -> dict[str, Any]: """ Add a phone number to a contact. POST /contacts/{id}/phones Args: contact_id: Contact ID phone: Phone number phone_type: Type (work, mobile, home, other) Returns: Created phone details """ return await make_request("POST", f"/contacts/{contact_id}/phones", json_data={"phone": phone, "type": phone_type}) @mcp.tool() async def update_contact_phone(contact_id: int, phone_id: int, phone: str, phone_type: str) -> dict[str, Any]: """ Update a contact's phone number. PUT /contacts/{id}/phones/{phone_id} Args: contact_id: Contact ID phone_id: Phone record ID phone: Updated phone number phone_type: Updated type (work, mobile, home, other) Returns: Updated phone details """ return await make_request("PUT", f"/contacts/{contact_id}/phones/{phone_id}", json_data={"phone": phone, "type": phone_type}) @mcp.tool() async def delete_contact_phone(contact_id: int, phone_id: int) -> dict[str, Any]: """ Delete a contact's phone number. DELETE /contacts/{id}/phones/{phone_id} Args: contact_id: Contact ID phone_id: Phone record ID Returns: Deletion confirmation """ return await make_request("DELETE", f"/contacts/{contact_id}/phones/{phone_id}") @mcp.tool() async def list_contact_pipelines(contact_id: int) -> dict[str, Any]: """ List all pipelines associated with a contact. GET /contacts/{id}/pipelines Args: contact_id: Contact ID Returns: List of contact pipelines """ return await make_request("GET", f"/contacts/{contact_id}/pipelines") @mcp.tool() async def list_contact_tags(contact_id: int) -> dict[str, Any]: """ List all tags applied to a contact. GET /contacts/{id}/tags Args: contact_id: Contact ID Returns: List of contact tags """ return await make_request("GET", f"/contacts/{contact_id}/tags") @mcp.tool() async def replace_contact_tags(contact_id: int, tag_ids: list[int]) -> dict[str, Any]: """ Replace all tags on a contact (replaces existing tags). PUT /contacts/{id}/tags Args: contact_id: Contact ID tag_ids: List of tag IDs to apply Returns: Updated tag list """ return await make_request("PUT", f"/contacts/{contact_id}/tags", json_data={"tag_ids": tag_ids}) @mcp.tool() async def attach_contact_tags(contact_id: int, tag_ids: list[int]) -> dict[str, Any]: """ Attach additional tags to a contact (additive). POST /contacts/{id}/tags Args: contact_id: Contact ID tag_ids: List of tag IDs to add Returns: Updated tag list """ return await make_request("POST", f"/contacts/{contact_id}/tags", json_data={"tag_ids": tag_ids}) @mcp.tool() async def delete_contact_tags(contact_id: int, tag_ids: list[int]) -> dict[str, Any]: """ Remove specific tags from a contact. DELETE /contacts/{id}/tags Args: contact_id: Contact ID tag_ids: List of tag IDs to remove Returns: Updated tag list """ return await make_request("DELETE", f"/contacts/{contact_id}/tags", json_data={"tag_ids": tag_ids}) # Contact Custom Fields Detail @mcp.tool() async def get_contact_custom_field(contact_id: int, field_id: int) -> dict[str, Any]: """ Get a specific custom field for a contact. GET /contacts/{id}/custom_fields/{field_id} Args: contact_id: Contact ID field_id: Custom field ID Returns: Custom field value """ return await make_request("GET", f"/contacts/{contact_id}/custom_fields/{field_id}") @mcp.tool() async def list_contact_custom_field_values(contact_id: int) -> dict[str, Any]: """ List all custom field values for a contact. GET /contacts/{id}/custom_field_values Args: contact_id: Contact ID Returns: List of custom field values """ return await make_request("GET", f"/contacts/{contact_id}/custom_field_values") @mcp.tool() async def get_contact_custom_field_value(contact_id: int, field_id: int) -> dict[str, Any]: """ Get a specific custom field value for a contact. GET /contacts/{id}/custom_field_values/{field_id} Args: contact_id: Contact ID field_id: Custom field ID Returns: Custom field value details """ return await make_request("GET", f"/contacts/{contact_id}/custom_field_values/{field_id}") # Contact Statuses @mcp.tool() async def list_contact_statuses() -> dict[str, Any]: """ List all available contact statuses. GET /contact_statuses Returns: List of contact statuses """ return await make_request("GET", "/contact_statuses") @mcp.tool() async def get_contact_status(contact_id: int) -> dict[str, Any]: """ Get the current status of a contact. GET /contacts/{id}/status Args: contact_id: Contact ID Returns: Current contact status """ return await make_request("GET", f"/contacts/{contact_id}/status") @mcp.tool() async def change_contact_status(contact_id: int, status_id: int, reason: Optional[str] = None) -> dict[str, Any]: """ Change the status of a contact. PUT /contacts/{id}/status Args: contact_id: Contact ID status_id: New status ID reason: Optional reason for change Returns: Updated contact with new status """ payload = {"status_id": status_id} if reason: payload["reason"] = reason return await make_request("PUT", f"/contacts/{contact_id}/status", json_data=payload) # Contact Lists @mcp.tool() async def list_contact_lists(per_page: int = 25, page: int = 1) -> dict[str, Any]: """ List all contact lists. GET /contact_lists Args: per_page: Results per page page: Page number Returns: List of contact lists """ return await make_request("GET", "/contact_lists", params={"per_page": per_page, "page": page}) @mcp.tool() async def get_contact_list(list_id: int) -> dict[str, Any]: """ Get a specific contact list. GET /contact_lists/{id} Args: list_id: List ID Returns: Contact list details """ return await make_request("GET", f"/contact_lists/{list_id}") @mcp.tool() async def create_contact_list(name: str, description: Optional[str] = None) -> dict[str, Any]: """ Create a new contact list. POST /contact_lists Args: name: List name description: List description Returns: Created contact list """ payload = {"name": name} if description: payload["description"] = description return await make_request("POST", "/contact_lists", json_data=payload) @mcp.tool() async def delete_contact_list(list_id: int) -> dict[str, Any]: """ Delete a contact list. DELETE /contact_lists/{id} Args: list_id: List ID Returns: Confirmation of deletion """ return await make_request("DELETE", f"/contact_lists/{list_id}") @mcp.tool() async def list_contact_list_items(list_id: int, per_page: int = 25, page: int = 1) -> dict[str, Any]: """ List all items in a contact list. GET /contact_lists/{id}/items Args: list_id: List ID per_page: Results per page page: Page number Returns: List of contact list items """ return await make_request("GET", f"/contact_lists/{list_id}/items", params={"per_page": per_page, "page": page}) @mcp.tool() async def get_contact_list_item(list_id: int, item_id: int) -> dict[str, Any]: """ Get a specific contact list item. GET /contact_lists/{list_id}/items/{item_id} Args: list_id: List ID item_id: Item ID Returns: Contact list item details """ return await make_request("GET", f"/contact_lists/{list_id}/items/{item_id}") @mcp.tool() async def create_contact_list_items(list_id: int, contact_ids: list[int]) -> dict[str, Any]: """ Add contacts to a list. POST /contact_lists/{id}/items Args: list_id: List ID contact_ids: List of contact IDs to add Returns: Created list items """ return await make_request("POST", f"/contact_lists/{list_id}/items", json_data={"contact_ids": contact_ids}) @mcp.tool() async def delete_contact_list_item(list_id: int, item_id: int) -> dict[str, Any]: """ Remove a contact from a list. DELETE /contact_lists/{list_id}/items/{item_id} Args: list_id: List ID item_id: Item ID Returns: Confirmation of deletion """ return await make_request("DELETE", f"/contact_lists/{list_id}/items/{item_id}") # Contact Thumbnails @mcp.tool() async def get_contact_thumbnail(contact_id: int) -> dict[str, Any]: """ Get a contact's thumbnail image. GET /contacts/{id}/thumbnail Args: contact_id: Contact ID Returns: Thumbnail image data """ return await make_request("GET", f"/contacts/{contact_id}/thumbnail") @mcp.tool() async def change_contact_thumbnail(contact_id: int, image_data: str) -> dict[str, Any]: """ Update a contact's thumbnail image. PUT /contacts/{id}/thumbnail Args: contact_id: Contact ID image_data: Base64 encoded image data or image URL Returns: Updated thumbnail information """ return await make_request("PUT", f"/contacts/{contact_id}/thumbnail", json_data={"image": image_data}) # ============================================================================= # ACTIVITIES TOOLSET (6 tools) # ============================================================================= def register_activities_tools(mcp: FastMCP, make_request): """Register all activities-related tools""" @mcp.tool() async def list_activities(per_page: int = 25, page: int = 1) -> dict[str, Any]: """ List all activities with pagination. GET /activities Activity types: email, meeting, call_talked, call_lvm, call_missed, text_message, other Args: per_page: Number of activities per page (default: 25, max: 100) page: Page number for pagination (default: 1) Returns: List of activities with pagination metadata """ return await make_request("GET", "/activities", params={"per_page": per_page, "page": page}) @mcp.tool() async def get_activity(activity_id: int) -> dict[str, Any]: """ Get detailed information about a specific activity. GET /activities/{id} Args: activity_id: Unique identifier for the activity Returns: Complete activity details including associated entities """ return await make_request("GET", f"/activities/{activity_id}") @mcp.tool() async def update_activity( activity_id: int, activity_type: Optional[str] = None, description: Optional[str] = None, notes: Optional[str] = None, completed: Optional[bool] = None ) -> dict[str, Any]: """ Update an existing activity. PUT /activities/{id} Args: activity_id: ID of activity to update activity_type: Updated type (email, meeting, call_talked, call_lvm, call_missed, text_message, other) description: Updated description notes: Updated notes completed: Mark as completed (true/false) Returns: Updated activity details """ payload = {} if activity_type: payload["type"] = activity_type if description: payload["description"] = description if notes: payload["notes"] = notes if completed is not None: payload["completed"] = completed return await make_request("PUT", f"/activities/{activity_id}", json_data=payload) @mcp.tool() async def delete_activity(activity_id: int) -> dict[str, Any]: """ Delete an activity record (permanent). DELETE /activities/{id} Args: activity_id: ID of activity to delete Returns: Deletion confirmation """ return await make_request("DELETE", f"/activities/{activity_id}") @mcp.tool() async def search_activities(query: str, per_page: int = 25) -> dict[str, Any]: """ Search activities by description or other criteria. GET /activities/search Args: query: Search query string per_page: Number of results per page (max: 100) Returns: List of matching activities """ return await make_request("GET", "/activities/search", params={"q": query, "per_page": per_page}) @mcp.tool() async def filter_activities( filters: dict[str, Any], per_page: int = 25, page: int = 1 ) -> dict[str, Any]: """ Filter activities using advanced criteria. POST /activities/search Args: filters: Dictionary of filter criteria (e.g., {"type": "meeting", "completed": false}) per_page: Results per page (max: 100) page: Page number Returns: Filtered list of activities """ payload = {**filters, "per_page": per_page, "page": page} return await make_request("POST", "/activities/search", json_data=payload) # ============================================================================= # PORTALS TOOLSET (8 tools) # ============================================================================= def register_portals_tools(mcp: FastMCP, make_request): """Register all portals-related tools""" @mcp.tool() async def list_portals(per_page: int = 25, page: int = 1) -> dict[str, Any]: """ List all job portals/boards. GET /portals Args: per_page: Number of portals per page (default: 25, max: 100) page: Page number for pagination (default: 1) Returns: List of configured job portals """ return await make_request("GET", "/portals", params={"per_page": per_page, "page": page}) @mcp.tool() async def get_portal(portal_id: int) -> dict[str, Any]: """ Get detailed information about a specific portal. GET /portals/{id} Args: portal_id: Unique identifier for the portal Returns: Complete portal details including configuration """ return await make_request("GET", f"/portals/{portal_id}") @mcp.tool() async def list_portal_jobs(portal_id: int, per_page: int = 25, page: int = 1) -> dict[str, Any]: """ List all jobs published to a specific portal. GET /portals/{id}/jobs Args: portal_id: Portal ID per_page: Results per page page: Page number Returns: List of jobs on the portal """ return await make_request("GET", f"/portals/{portal_id}/jobs", params={"per_page": per_page, "page": page}) @mcp.tool() async def submit_job_application( portal_id: int, job_id: int, candidate_data: dict[str, Any] ) -> dict[str, Any]: """ Submit a job application through a portal. POST /portals/{portal_id}/jobs/{job_id}/apply Args: portal_id: Portal ID job_id: Job posting ID candidate_data: Candidate information (first_name, last_name, email, resume, etc.) Returns: Created application details """ return await make_request("POST", f"/portals/{portal_id}/jobs/{job_id}/apply", json_data=candidate_data) @mcp.tool() async def publish_job_to_portal(portal_id: int, job_id: int) -> dict[str, Any]: """ Publish a job posting to a portal. POST /portals/{portal_id}/jobs/{job_id}/publish Args: portal_id: Portal ID job_id: Job posting ID Returns: Publishing confirmation """ return await make_request("POST", f"/portals/{portal_id}/jobs/{job_id}/publish") @mcp.tool() async def unpublish_job_from_portal(portal_id: int, job_id: int) -> dict[str, Any]: """ Remove a job posting from a portal. DELETE /portals/{portal_id}/jobs/{job_id}/publish Args: portal_id: Portal ID job_id: Job posting ID Returns: Unpublishing confirmation """ return await make_request("DELETE", f"/portals/{portal_id}/jobs/{job_id}/publish") @mcp.tool() async def get_portal_registration(portal_id: int) -> dict[str, Any]: """ Get portal registration information and requirements. GET /portals/{id}/registration Args: portal_id: Portal ID Returns: Portal registration details """ return await make_request("GET", f"/portals/{portal_id}/registration") @mcp.tool() async def submit_portal_registration( portal_id: int, registration_data: dict[str, Any] ) -> dict[str, Any]: """ Submit portal registration information. POST /portals/{id}/registration Args: portal_id: Portal ID registration_data: Registration information (varies by portal) Returns: Registration confirmation """ return await make_request("POST", f"/portals/{portal_id}/registration", json_data=registration_data) # ============================================================================= # WORK HISTORY TOOLSET (3 tools) # ============================================================================= def register_work_history_tools(mcp: FastMCP, make_request): """Register all work history-related tools""" @mcp.tool() async def get_work_history(work_history_id: int) -> dict[str, Any]: """ Get detailed information about a specific work history entry. GET /work_history/{id} Args: work_history_id: Unique identifier for the work history entry Returns: Complete work history details Note: Work history entries are typically accessed through candidate sub-resources. Creation happens via: POST /candidates/{id}/work_history """ return await make_request("GET", f"/work_history/{work_history_id}") @mcp.tool() async def update_work_history( work_history_id: int, company_name: Optional[str] = None, title: Optional[str] = None, start_date: Optional[str] = None, end_date: Optional[str] = None, description: Optional[str] = None, currently_employed: Optional[bool] = None ) -> dict[str, Any]: """ Update an existing work history entry. PUT /work_history/{id} Args: work_history_id: ID of work history to update company_name: Updated company name title: Updated job title start_date: Updated start date (YYYY-MM-DD) end_date: Updated end date (YYYY-MM-DD, null if currently employed) description: Updated job description currently_employed: Whether candidate is currently employed here Returns: Updated work history details """ payload = {} if company_name: payload["company_name"] = company_name if title: payload["title"] = title if start_date: payload["start_date"] = start_date if end_date: payload["end_date"] = end_date if description: payload["description"] = description if currently_employed is not None: payload["currently_employed"] = currently_employed return await make_request("PUT", f"/work_history/{work_history_id}", json_data=payload) @mcp.tool() async def delete_work_history(work_history_id: int) -> dict[str, Any]: """ Delete a work history entry (permanent). DELETE /work_history/{id} Args: work_history_id: ID of work history to delete Returns: Deletion confirmation """ return await make_request("DELETE", f"/work_history/{work_history_id}") # ============================================================================= # REGISTRATION FUNCTION # ============================================================================= def register_all_recruiting_toolsets(mcp: FastMCP, make_request): """ Register all recruiting toolsets with the MCP server. This includes: - Companies (18 tools) - Contacts (18 tools) - Activities (6 tools) - Portals (8 tools) - Work History (3 tools) Total: 53 tools Args: mcp: FastMCP server instance make_request: HTTP request helper function """ register_companies_tools(mcp, make_request) register_contacts_tools(mcp, make_request) register_activities_tools(mcp, make_request) register_portals_tools(mcp, make_request) register_work_history_tools(mcp, make_request)

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/vanman2024/cats-mcp-server'

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