Un MCP server afinado para equipos de customer success que usan HubSpot. Expone contacts, companies, tickets y deals como herramientas de Claude, con helpers específicos de CS para queries de fecha de renovación, aging de tickets y lecturas de health-score. El CSM pregunta “qué está en riesgo este mes” y Claude jala los datos reales.
Lo que vas a necesitar
HubSpot Sales Hub Pro o superior, con Service Hub para tickets
Un token de Private App de HubSpot con scopes de lectura para contacts, companies, deals y tickets
Claude Desktop o Claude Code como cliente MCP
Una convención de campo de health-score acordada con tu liderazgo de CS
Setup
Corre el server. La implementación de referencia es Python, estilo FastAPI. Clona, instala, configura HUBSPOT_TOKEN y HUBSPOT_PORTAL_ID. El server arranca en stdio para Claude Desktop local o en HTTP para clientes hosted.
Configura las herramientas helper. Tres helpers específicos de CS vienen por defecto: at_risk_renewals, aging_tickets, accounts_needing_qbr. Cada una mapea a una query parametrizada de HubSpot. Edita las plantillas de query para que coincidan con tus campos.
Agrega al config del cliente MCP. Apunta Claude Desktop al server. Al arrancar deberías ver alrededor de doce herramientas registradas.
Configura el campo de health-score. La mayoría de los equipos usan una propiedad numérica custom. Pasa su nombre interno al server para que los helpers puedan filtrar sobre ella.
Corre “muéstrame las renovaciones en riesgo en los próximos noventa días”. Verifica la salida contra la misma query en la UI de HubSpot.
Cómo funciona
El server es de lectura mayoritaria por diseño. Los workflows de CS son sobre saber qué está pasando, no sobre mutación masiva de registros. La superficie de herramientas por defecto incluye lecturas de objeto, recorrido de asociaciones (contact a company a deals a tickets) y los tres helpers específicos de CS.
Las escrituras se limitan a creación de tickets y notas. Sin cambios de stage de deal, sin merges de contactos, sin updates de propiedades en companies. El principio: Claude puede preguntar, resumir y documentar, pero el CSM sigue manejando los cambios reales hacia el cliente.
Cuídate de
Drift del campo de health-score. Los equipos cambian la fórmula cada trimestre. El server no cachea nada; las queries pegan la propiedad en vivo. Actualiza los docs de los helpers cuando la fórmula cambie para que los prompts sigan siendo precisos.
Volumen de tickets. Las queries de aging-tickets pueden devolver miles de filas en portales activos. El helper pagina y limita a quinientos por defecto. Ajusta para tu volumen.
Joins entre objetos. La API de associations de HubSpot es más lenta que las queries directas. El server agrupa associations pero un recorrido de deal-a-tickets a través de mil deals tarda minutos, no segundos.
Permisos. Los tokens de Private App brincan los permisos a nivel usuario. Cualquiera con acceso al cliente MCP ve toda la data. Documéntalo claro con tu equipo de seguridad.
Stack
HubSpot — fuente de verdad de CRM y ticketing
MCP server — capa de lectura, herramientas helper, superficie ligera de escritura
Claude — interfaz de lenguaje natural para el equipo de CS
# mcp-server-hubspot-cs
An MCP server tuned for customer success teams using HubSpot. Exposes contacts, companies, tickets, and deals as Claude tools, plus three CS-specific helpers: `at_risk_renewals`, `aging_tickets`, `accounts_needing_qbr`.
> **STATUS: scaffold — not runtime-tested.** The code below is structurally
> complete and follows the official `mcp` Python SDK conventions, but it
> has not been executed against a live HubSpot portal. Treat it as a
> starting point you adapt to your portal's field conventions, not as a
> deployable binary. Health-score field names, custom property paths, and
> association labels vary by portal.
## What it exposes
### Object-read tools (read-only)
- `get_contact(contact_id)` — full contact properties
- `get_company(company_id)` — full company properties + associated contacts
- `get_deal(deal_id)` — full deal properties + associated contacts/company
- `get_ticket(ticket_id)` — full ticket properties + associated company
### Search tools (read-only)
- `search_contacts(query, limit?)`
- `search_companies(query, limit?)`
- `search_deals(filters, limit?)`
- `search_tickets(filters, limit?)`
### CS-specific helpers (read-only)
- `at_risk_renewals(window_days=90)` — deals in renewal stages closing in the window, filtered by configured health-score threshold
- `aging_tickets(min_age_hours=48, limit=500)` — open tickets older than the threshold, grouped by company
- `accounts_needing_qbr(months_since_last=3)` — companies with no recorded QBR activity in the window
### Light-write tools (CSM-driven)
- `create_ticket(subject, body, company_id?)` — open a new ticket
- `add_note(object_type, object_id, body)` — append a note to a record
The server **does not** expose deal-stage changes, contact merges, or company property updates. The principle: Claude can ask, summarize, and document; the CSM drives every customer-facing change.
## Setup
### 1. Install
```bash
git clone <wherever you put this>
cd mcp-server-hubspot-cs
python -m venv .venv
source .venv/bin/activate # or .venv\Scripts\activate on Windows
pip install -e .
```
### 2. Create a HubSpot Private App token
In HubSpot: Settings → Integrations → Private Apps → Create. Grant these scopes:
- `crm.objects.contacts.read`
- `crm.objects.companies.read`
- `crm.objects.deals.read`
- `tickets` (read)
- `crm.objects.contacts.write` (only for `add_note`)
- `tickets` (write — only for `create_ticket`)
Copy the access token.
### 3. Configure environment
```bash
export HUBSPOT_TOKEN="pat-na1-..."
export HUBSPOT_PORTAL_ID="12345678"
export HUBSPOT_HEALTH_SCORE_PROPERTY="health_score" # your custom field
export HUBSPOT_RENEWAL_STAGE_IDS="appointmentscheduled,qualifiedtobuy"
export HUBSPOT_RENEWAL_HEALTH_THRESHOLD="60" # below = at risk
```
The renewal stage IDs are pipeline-specific. Look them up in HubSpot → Settings → Pipelines.
### 4. Register with Claude Desktop
Edit `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows):
```json
{
"mcpServers": {
"hubspot-cs": {
"command": "python",
"args": ["-m", "hubspot_cs_mcp.server"],
"env": {
"HUBSPOT_TOKEN": "pat-na1-...",
"HUBSPOT_PORTAL_ID": "12345678",
"HUBSPOT_HEALTH_SCORE_PROPERTY": "health_score",
"HUBSPOT_RENEWAL_STAGE_IDS": "appointmentscheduled,qualifiedtobuy",
"HUBSPOT_RENEWAL_HEALTH_THRESHOLD": "60"
}
}
}
}
```
Restart Claude Desktop. You should see ~12 tools registered under `hubspot-cs`.
### 5. Sanity-check
Ask Claude: "Show me at-risk renewals in the next ninety days." Compare the output against the equivalent query in HubSpot's UI. Tune the `HUBSPOT_RENEWAL_HEALTH_THRESHOLD` and stage IDs until they match.
## Watch-outs
- **Private App tokens bypass user-level permissions.** Anyone with access to the MCP client sees every record the token can reach. Document this with your security team.
- **Health-score field drift.** Teams change the formula every quarter. Update `HUBSPOT_HEALTH_SCORE_PROPERTY` and the threshold when the formula changes.
- **Aging-ticket queries can return thousands of rows.** The helper paginates and caps at 500 by default. Tune for your portal volume.
- **Cross-object joins are slow.** A deal-to-tickets traversal across a thousand deals takes minutes — HubSpot's association API is the bottleneck.
## Limits and TODOs (before production use)
- [ ] Add request-level retries with exponential backoff (HubSpot returns 429 readily under sustained load).
- [ ] Write integration tests against a HubSpot sandbox portal.
- [ ] Add structured logging via `python-json-logger`.
- [ ] Wire optional Sentry / OpenTelemetry export.
- [ ] Validate every helper query against the actual portal's pipeline configuration on first run, fail loud if the configured stage IDs do not exist.