This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
HubSpot MCP Server - A Model Context Protocol (MCP) server that enables AI assistants to interact with HubSpot CRM data. This is a Python-based MCP server designed for Docker deployment with built-in FAISS vector storage for semantic search and caching.
# Install in development mode
pip install -e .
# Run the server locally (requires HUBSPOT_ACCESS_TOKEN environment variable)
mcp-server-hubspot
# Or with explicit access token
mcp-server-hubspot --access-token YOUR_TOKEN# Build Docker image
docker build -t mcp-hubspot .
# Build multi-platform image
docker buildx create --use
docker buildx build --platform linux/amd64,linux/arm64 -t buryhuang/mcp-hubspot:latest --push .
# Run Docker container
docker run -e HUBSPOT_ACCESS_TOKEN=your_token -v /path/to/storage:/storage buryhuang/mcp-hubspot:latestTests are located in the tests/ directory:
test_closed_tickets.py- Tests for closed ticket retrievaltest_mcp_ticket_conversations.py- Tests for ticket conversation threadsget_closed_ticket_conversations.py- Utility script for testing conversation retrieval
Run tests directly with Python (no test runner configured in pyproject.toml).
-
Server Layer (
server.py)- MCP protocol implementation using
mcp.server.stdio - Tool registration and routing
- Initialization of dependencies (HubSpot client, FAISS manager, embedding model)
- Single entry point that composes all handlers
- MCP protocol implementation using
-
Handler Layer (
handlers/)- Domain-specific handlers extending
BaseHandler - Each handler manages MCP tool schemas and executes tool calls
- Handlers:
CompanyHandler,ContactHandler,ConversationHandler,TicketHandler,SearchHandler,PropertyHandler - Responsible for FAISS storage integration via
store_in_faiss_safely()
- Domain-specific handlers extending
-
Client Layer (
clients/)- Direct HubSpot API interaction via
hubspot-api-client - Domain-specific clients:
CompanyClient,ContactClient,ConversationClient,TicketClient,PropertyClient - Composed by
HubSpotClientwhich delegates to specialized clients
- Direct HubSpot API interaction via
FAISS Manager (faiss_manager.py)
- Rolling storage by day (configurable max_days, default 7)
- Maintains separate indexes per date:
index_YYYY-MM-DD.faissandmetadata_YYYY-MM-DD.json - Automatically loads recent indexes on initialization and removes old ones
- Uses
faiss.IndexFlatL2with configurable embedding dimension (default: 384)
Embedding Model
- Uses SentenceTransformer with
all-MiniLM-L6-v2model (384 dimensions) - Pre-downloaded in Docker image to
/app/models/all-MiniLM-L6-v2 - Falls back to HuggingFace download if local model not found
Storage System
- Default storage directory:
/storage(Docker) orstorage/(local) - Configurable via
HUBSPOT_STORAGE_DIR_LOCALenvironment variable ThreadStoragecaches conversation threads instorage/conversation_threads.json- FAISS indexes stored per-day for semantic search across HubSpot data
- Handler receives MCP tool call → validates arguments
- Handler calls appropriate client method → gets HubSpot data
- Handler stores data in FAISS → calls
store_in_faiss_safely() - FAISS manager adds vectors and metadata → saves to disk
- Handler returns formatted response to MCP client
Error Handling
ApiExceptionfromhubspot.crm.contacts.exceptionsis caught at server level- Handlers use
core/error_handler.pyfor consistent error responses - All FAISS operations wrapped in try-catch with logging
Formatters
core/formatters.pyprovidesconvert_datetime_fields()for HubSpot datetime normalization- Used throughout clients to ensure consistent date formatting
Duplicate Prevention
- Contact and company creation include duplicate checking before API calls
- Uses property-based matching (email for contacts, domain/name for companies)
HUBSPOT_ACCESS_TOKEN(required) - HubSpot API access tokenHUBSPOT_STORAGE_DIR_LOCAL(optional) - Override default storage directory, defaults to/storage
Core dependencies (from pyproject.toml):
mcp>=1.4.1- Model Context Protocol SDKhubspot-api-client>=11.1.0- Official HubSpot API clientfaiss-cpu>=1.7.4- Vector similarity searchsentence-transformers>=2.2.2- Embedding generationhuggingface-hub==0.14.1- Model downloads (pinned version)python-dotenv>=1.0.1- Environment variable loading
The access token must have these scopes:
crm.objects.contacts(read/write)crm.objects.companies(read/write)sales-email-read
hubspot_create_contact- Create contacts with duplicate preventionhubspot_get_active_contacts- Retrieve most recently active contactshubspot_get_contact- Get a specific contact by ID (with optional properties filter)hubspot_update_contact- Update an existing contact record
hubspot_create_company- Create companies with duplicate preventionhubspot_get_company_activity- Retrieve activity for specific companieshubspot_get_active_companies- Retrieve most recently active companieshubspot_get_company- Get a specific company by ID (with optional properties filter)hubspot_update_company- Update an existing company record
hubspot_get_recent_conversations- Retrieve conversation threads with messages
hubspot_get_tickets- Get tickets with configurable criteria ("default" or "Closed")hubspot_get_ticket_conversation_threads- Get conversation threads for a specific ticket
hubspot_get_property- Get details of a specific HubSpot property definitionhubspot_update_property- Update a HubSpot property definition (e.g., add dropdown options)hubspot_create_property- Create a new custom property in HubSpot
hubspot_search_data- Semantic search across stored HubSpot data via FAISS