HubSpot CRM MCP Server

Servidor MCP do HubSpot CRM: contatos, negócios, pipelines. Gravações idempotentes e trilha de auditoria completa.

Documentação

Servidor MCP do HubSpot CRM

CI License: MIT

Servidor MCP do HubSpot CRM para Claude Desktop e qualquer cliente MCP, compatível com o plano gratuito. 15 ferramentas para contatos, negócios e pipelines, autenticadas com um token de aplicativo privado do HubSpot ou um aplicativo OAuth completo. Gravações são idempotentes, então uma chamada de ferramenta repetida reproduz seu primeiro resultado em vez de criar um registro duplicado, e cada chamada de ferramenta é registrada em uma trilha de auditoria com PII removido, incluindo as chamadas negadas por escopo ausente e as chamadas que falharam.

Relacionados: Servidor MCP do QuickBooks Online · Gateway de Auditoria MCP · O que o MCP de produção realmente exige

O HubSpot executa um servidor MCP hospedado próprio, com cobertura de objetos mais ampla que este. Ele é feito para auto-hospedagem: você executa o processo, o código-fonte é curto o suficiente para ser lido em uma sentada, e a trilha de auditoria, o cache e as credenciais nunca saem da sua infraestrutura.

O resto é o que um wrapper REST geralmente deixa de fora. Ele solicita o escopo ausente exato em vez de vazar um 403 bruto, tenta novamente limites de taxa com backoff, atende leituras de registros de um cache local (TTL mais invalidação por gravação, com um manipulador de webhook verificado por assinatura que você pode conectar ao seu próprio ingress HTTP para alterações fora de banda), percorre paginação por cursor e retorna resultados por item quando um lote falha parcialmente.

Veja docs/COMPARISON.md para transcrições lado a lado de um wrapper de API ingênuo em MCP versus este. Cada transcrição é gerada executando ambos contra a suíte de testes simulada.

Arquitetura

flowchart TD
    Agent["MCP client / agent"] -->|"stdio (JSON-RPC)"| Server["FastMCP server<br/>server.py"]
    Server --> Service["CrmService<br/>scope checks · audit · orchestration"]

    Service --> Cache["LocalCache<br/>TTL + write invalidation"]
    Service --> Idem["Idempotency store"]
    Service --> Audit["Audit log<br/>PII redaction"]
    Service --> Client["HubSpotClient<br/>retries · pagination · error mapping"]

    Client --> Auth["Token provider<br/>private-app · OAuth refresh"]
    Client -->|HTTPS| HubSpot["HubSpot CRM API"]

    Ingress["Your HTTP ingress<br/>(optional, host-provided)"] -->|"signed v3 payload"| Processor["WebhookProcessor<br/>verify_signature"]
    Processor -->|"invalidate(object)"| Cache

O servidor stdio fala apenas JSON-RPC; ele não escuta webhooks. WebhookProcessor e verify_signature são fornecidos como um componente testado que você monta no seu próprio ingress HTTP (veja Invalidação de cache por webhook).

Ferramentas

Cada ferramenta carrega anotações MCP (readOnlyHint, destructiveHint, idempotentHint, openWorldHint), um esquema de entrada descrito e um esquema de saída.

FerramentaO que fazEscopo
crm_search_contactsPesquisa contatos por termo de texto livre, uma página por vezcrm.objects.contacts.read
crm_list_contactsLista contatos em ordem de id com paginação por cursorcrm.objects.contacts.read
crm_get_contactBusca um contato por id, servido do cache localcrm.objects.contacts.read
crm_create_contactCria um contato, idempotente em uma chave fornecida ou derivadacrm.objects.contacts.write
crm_update_contactSobrescreve as propriedades passadas e invalida a entrada do cachecrm.objects.contacts.write
crm_delete_contactArquiva (exclusão suave) um contatocrm.objects.contacts.write
crm_batch_create_contactsCria até 100 contatos e relata falhas por linhacrm.objects.contacts.write
crm_search_dealsPesquisa negócios por termo de texto livre com paginação por cursorcrm.objects.deals.read
crm_get_dealBusca um negócio por id, servido do cache localcrm.objects.deals.read
crm_create_dealCria um negócio, idempotente em uma chave fornecida ou derivadacrm.objects.deals.write
crm_update_dealAtualiza propriedades do negócio, incluindo movê-lo para outro estágiocrm.objects.deals.write
crm_delete_dealArquiva (exclusão suave) um negóciocrm.objects.deals.write
crm_list_pipelinesLista pipelines de negócios com estágios em ordem de exibição (em cache)crm.schemas.deals.read
crm_get_pipelineBusca um pipeline com seus estágios ordenadoscrm.schemas.deals.read
crm_export_audit_logExporta a trilha de auditoria da sessão como JSON Linesnenhum

Início rápido

Execute sem instalar nada permanente:

uvx mcp-hubspot

Ou instale:

pip install mcp-hubspot
mcp-hubspot

Qualquer forma fala MCP sobre stdio em stdin e stdout. Autentique com um token de aplicativo privado (HUBSPOT_PRIVATE_APP_TOKEN) ou um aplicativo OAuth (HUBSPOT_CLIENT_ID + HUBSPOT_CLIENT_SECRET + HUBSPOT_REFRESH_TOKEN). O servidor detecta automaticamente qual está presente.

As credenciais são resolvidas de forma preguiçosa. O servidor inicia e responde a initialize e tools/list com nada configurado, o que é o que permite que um diretório ou um sandbox o inspecione; a primeira chamada de ferramenta é onde uma credencial ausente se transforma em um erro acionável.

Conectando a um cliente MCP

Adicione à configuração do seu host MCP (por exemplo, o claude_desktop_config.json do Claude Desktop):

{
  "mcpServers": {
    "hubspot": {
      "command": "uvx",
      "args": ["mcp-hubspot"],
      "env": { "HUBSPOT_PRIVATE_APP_TOKEN": "pat-na1-..." }
    }
  }
}

Docker

docker build -t mcp-hubspot .
docker run --rm -i -e HUBSPOT_PRIVATE_APP_TOKEN=pat-na1-... mcp-hubspot

A partir do código-fonte

Requer Python 3.12+ e uv.

uv venv
uv pip install -e ".[dev]"

cp .env.example .env   # then fill in your HubSpot credentials
uv run mcp-hubspot

URL de autorização OAuth

Para o fluxo OAuth, mcp_crm.auth.build_authorization_url(...) constrói a URL de consentimento com os escopos que as ferramentas precisam; troque o código retornado por um token de atualização e defina HUBSPOT_REFRESH_TOKEN.

Invalidação de cache por webhook

O servidor stdio não recebe webhooks. Para invalidar o cache em alterações feitas fora deste processo (edições na interface do HubSpot, outras integrações), monte WebhookProcessor no seu próprio endpoint HTTP e verifique a assinatura v3 do HubSpot com verify_signature (usando o HUBSPOT_WEBHOOK_SECRET que você configura). Aponte-o para o mesmo LocalCache que seu CrmService usa:

from mcp_crm.webhooks import WebhookProcessor, verify_signature

processor = WebhookProcessor(cache)

def handle_hubspot_webhook(request):
    ok = verify_signature(
        secret=webhook_signing_secret,
        method="POST",
        uri=request.url,
        body=request.raw_body,
        signature=request.headers["X-HubSpot-Signature-v3"],
        timestamp=request.headers["X-HubSpot-Request-Timestamp"],
    )
    if not ok:
        return 401
    processor.process(request.json())
    return 200

verify_signature rejeita corpos adulterados, segredos errados e timestamps obsoletos; WebhookProcessor.process mapeia cada assinatura para o objeto que ela invalida e relata o que tocou.

Decisões de design

  • Escopo do cache. Apenas leituras de detalhes de objetos (crm_get_contact, crm_get_deal) e a lista de pipelines são armazenadas em cache; resultados de lista/pesquisa dependem da consulta e ficam sem cache para evitar servir conjuntos de resultados obsoletos. Gravações invalidam o objeto relevante imediatamente. Para alterações fora de banda, um WebhookProcessor verificado por assinatura é fornecido como um componente que você monta no seu próprio ingress HTTP (veja Invalidação de cache por webhook); o servidor stdio em si não escuta webhooks.
  • Idempotência é do lado do cliente. Os endpoints de criação do HubSpot não são nativamente idempotentes, então uma chave (fornecida ou derivada do payload) é armazenada e reproduzida. Isso torna tentativas de ferramenta pelo menos uma vez seguras sem duplicar registros. O armazenamento vive no processo, então cobre tentativas dentro de uma sessão em vez de reinicializações, e crm_batch_create_contacts deliberadamente não o usa; ambos os fatos são declarados nas descrições das ferramentas.
  • Solicitação de escopo acontece duas vezes. O serviço pré-verifica escopos concedidos (via introspecção de token) para um erro rápido e acionável, e o cliente HTTP também mapeia um MISSING_SCOPES 403 do lado do servidor para o mesmo erro tipado (cinto e suspensórios).
  • Credenciais carregam de forma preguiçosa. Nada lê um token na importação ou na inicialização. Uma credencial ausente aparece como um erro tipado na primeira chamada de ferramenta, e essa falha é auditada como qualquer outra, então o servidor ainda é inspecionável em um sandbox com um ambiente vazio.
  • Backoff e relógios são injetáveis. Sono de tentativa, jitter de RNG e fontes de tempo são parâmetros de construtor, que é o motivo pelo qual toda a suíte roda offline em bem menos de um segundo.

Testes

Cada chamada externa ao HubSpot é atendida por um fake em memória (tests/fake_hubspot.py) apoiado por fixtures JSON (tests/fixtures/), conectado via httpx.MockTransport. Sem rede, sem credenciais, determinístico.

uv run pytest -q

Regenere o documento de comparação (o CI também verifica se ele permanece sincronizado):

uv run python scripts/generate_comparison.py

Metadados do registro

server.json descreve este pacote para o registro do Model Context Protocol (io.github.amin-ale/hubspot-crm-mcp, PyPI mcp-hubspot, transporte stdio). .mcp.json é a configuração mínima de cliente para ferramentas que detectam automaticamente servidores MCP a partir da raiz de um repositório.

Escopo e segurança

Este é um cliente para dados do HubSpot que você possui ou está autorizado a acessar. Aponte-o apenas para contas do HubSpot que você controla ou tem permissão escrita para operar. O log de auditoria remove emails e números de telefone antes de gravar registros; trate logs de auditoria exportados como sensíveis independentemente. O comportamento documentado aqui é pontual em relação às fixtures incluídas, não uma garantia sobre qualquer conta HubSpot ao vivo.

Contrate-me

Eu construo servidores MCP e integrações de API que sobrevivem a uma revisão de código de desenvolvedor sênior: autenticação, tentativas, idempotência e trilhas de auditoria incluídas, não adicionadas depois. Portfólio e contato: https://amin-ale.github.io/portfolio-site · amin.ale.business@gmail.com.