HubSpot Integration Architecture
Technical architecture and design decisions for the HubSpot integration.
Overview
The integration uses a hybrid approach:
- HubSpot MCP Server: Read operations via natural language
- HubSpot API Service: Write operations and enrichment logic
- Enrichment Layer: On-demand Linear ticket enrichment
Architecture Diagram
┌─────────────────────────────────────────┐
│ Cursor IDE │
│ (Natural Language Interface) │
└──────────────┬──────────────────────────┘
│
┌───────┴────────┐
│ │
▼ ▼
┌──────────────┐ ┌──────────────────┐
│ HubSpot MCP │ │ HubSpot API │
│ Server │ │ Service │
│ │ │ │
│ Read-only │ │ Read + Write │
│ Queries │ │ Enrichment │
└──────┬───────┘ └────────┬──────────┘
│ │
└──────────┬────────┘
│
┌────────▼────────┐
│ HubSpot CRM │
│ │
│ - Deals │
│ - Contacts │
│ - Companies │
│ - Associations │
└─────────────────┘
│
│
┌────────▼────────┐
│ Linear Tickets │
│ (Enriched) │
└─────────────────┘
Components
1. HubSpot MCP Server
Purpose: Natural language read operations
Technology: Remote MCP server at https://mcp.hubspot.com/
Authentication: OAuth 2.1 with PKCE
Capabilities:
- Query deals, contacts, companies
- Search CRM objects
- Get object details
- Read-only access
Limitations:
- Read-only (no writes)
- Rate limited (100 requests per 10 seconds)
2. HubSpot API Service
Purpose: Write operations and enrichment logic
Technology: Node.js + TypeScript + @hubspot/api-client
Authentication: Private App access token
Capabilities:
- Create/update/delete deals
- Manage contacts and companies
- Traverse associations
- Enrichment logic
Rate Limiting:
- Configured via SDK: ~9 requests/second
- Automatic retry for 429 and 5xx errors
- Max 6 concurrent requests
3. Enrichment Layer
Purpose: On-demand Linear ticket enrichment
Components:
enrich-ticket.ts: Fetch HubSpot contextformat-context.ts: Format context as markdownlink-ticket.ts: Link tickets to deals
Flow:
- Extract ticket context (title, description, ID)
- Search for matching HubSpot deal
- Fetch deal with associations
- Format as markdown
- Add to Linear ticket
Data Flow
Enrichment Flow
Linear Ticket
│
├─ Extract: title, description, ticket ID
│
├─ Search HubSpot:
│ ├─ By Linear ticket ID
│ ├─ By company name
│ └─ By deal name
│
├─ Fetch Context:
│ ├─ Deal details
│ ├─ Associated contacts
│ ├─ Associated company
│ └─ Company contacts (optional)
│
└─ Format & Add:
└─ Markdown context → Linear ticket
Write Flow
Natural Language Command
│
├─ Parse intent:
│ ├─ Create deal
│ ├─ Update deal
│ ├─ Add note
│ └─ Link ticket
│
├─ Validate & Confirm:
│ ├─ Show preview
│ └─ Request confirmation
│
└─ Execute:
└─ API call → HubSpot CRM
Association Traversal
The system traverses HubSpot associations to build full context:
Deal
├─→ Contacts (via Deal-Contact association)
│ └─→ Contact details
│
└─→ Company (via Deal-Company association)
├─→ Company details
└─→ Company Contacts (via Company-Contact association)
└─→ Additional contact details
Use Case: “Show me everything about the Inteleos opportunity”
Returns:
- Deal information
- Primary contacts on the deal
- Associated company
- All contacts at the company
Pipeline Inference
When creating/updating deals, the system infers the pipeline:
Inference Rules:
- Check deal properties (industry, type)
- Check ticket labels (enterprise, nonprofit, etc.)
- Check ticket context (client type, engagement type)
- Default to “Sales Pipeline” if uncertain
- Prompt user if multiple options possible
Example:
- Ticket label: “nonprofit” → Nonprofit Pipeline
- Deal property: “enterprise” → Enterprise Pipeline
- No match → Ask user
Error Handling
Retry Logic
The API service includes automatic retry:
- 429 (Rate Limit): Retry after 10 seconds
- 5xx (Server Error): Retry with exponential backoff
- Max Retries: 3 attempts
Error Types
- Deal Not Found: Suggest creating new deal
- Multiple Matches: Show list, ask user to select
- Rate Limited: Automatic retry with delay
- Authentication Error: Prompt to update token
- Validation Error: Show specific field errors
Security
Authentication
- MCP: OAuth 2.1 with PKCE (handled by MCP client)
- API Service: Private App token (stored in environment)
Token Storage
- Never commit tokens to git
- Use environment variables
.envfiles in.gitignore
Access Control
- MCP: User-level permissions (based on HubSpot user)
- API Service: Private app scopes (configured in HubSpot)
Performance
Rate Limiting
- MCP: 100 requests per 10 seconds (HubSpot limit)
- API Service: ~9 requests/second (conservative)
Caching
Considerations for future:
- Cache deal lookups
- Cache association data
- TTL-based invalidation
Optimization
- Batch association requests
- Parallel API calls where possible
- Lazy loading of optional data
Deployment
API Service Options
-
Standalone Service (Railway, Render)
- Deploy as Node.js service
- Environment variables for config
- HTTP endpoints for operations
-
Platform Integration
- Part of existing platform
- Shared infrastructure
- Integrated auth
-
Serverless (with modifications)
- AWS Lambda, Vercel Functions
- Stateless operations
- Cold start considerations
Future Enhancements
- Webhook Support: Real-time updates from HubSpot
- Bidirectional Sync: Optional auto-sync (if needed)
- Caching Layer: Redis for performance
- Batch Operations: Bulk updates
- Analytics: Track enrichment usage
- AI Suggestions: Auto-suggest enrichments
Dependencies
@hubspot/api-client: Official HubSpot SDKdotenv: Environment variable management- TypeScript: Type safety