Skip to main content
Glama
HubSpot MCP Agent with Slack Approval

HubSpot MCP Agent with Slack Approval

by rubianaseem

HubSpot MCP Agent with Slack Approval

A Claude agent that researches accounts through an MCP server, drafts HubSpot updates, and cannot write a single field until a named person clicks Approve in Slack on the exact change they were shown.

Built by Rubia Naseem, GTM Engineer (12+ yrs CRM/RevOps, HubSpot & Salesforce).

The problem

Connecting Claude to a CRM through MCP is easy. Making it safe is the part most demos skip. "The agent asks before it writes" usually means a confirmation dialog in the chat client, and the MCP spec says clients "MUST consider tool annotations to be untrusted unless they come from trusted servers", and there "SHOULD always be a human in the loop with the ability to deny tool invocations" (MCP tools spec).

In RevOps the failures are specific. A scraped web page tells the agent to change the owner. Someone approves Tuesday's draft and Wednesday's regenerated version goes in. A rep edits the record between approval and write. A 429 retry creates the same note twice. I've built signal-triggered routing in production, and these details decide whether anyone trusts the automation. So here the approval lives on the server, not in the chat window.

Related MCP server: Cadence

What it does

  • Exposes seven MCP tools for reading, drafting, requesting approval and applying. There is no approve tool, so the model cannot approve its own work.

  • Scores buying signals, picks a play and drafts a property update, note and owner task. Optional Claude classifies messy signal text, and every quote it uses is checked against the source.

  • Quarantines signal text that reads like instructions, redacts emails, and refuses any property outside a five-field allowlist.

  • Posts a Slack Block Kit message whose button carries the proposal's SHA-256 content hash. Clicks are checked against Slack's signing secret, a 5-minute replay window and per-approver permissions.

  • Releases approved changes with idempotency keys, Retry-After handling, backoff, stale-record checks and crash resume, all logged to a hash-chained audit file.

Where each step runs

  1. GitHub stores the code. You run it from Terminal, Mac Terminal or the Cursor terminal.

  2. agent.py draft starts the agent, which talks to the MCP server (mcp_server.py). With ANTHROPIC_API_KEY set, Claude drives that tool loop. Without it, a scripted loop calls the same tools.

  3. Approval requests go to a local Slack outbox by default, or to your Slack channel with --live-slack.

  4. slack_server.py receives the button click and records the decision. It never writes to the CRM.

  5. A person runs agent.py apply --proposal ... to release one approved proposal. Today that write goes to a mock HubSpot file (state/crm.json), not a real portal.

Guardrails and human in the loop

  • Planning, approval and execution are three separate steps, and only the last one writes.

  • An approval binds to the content hash and record version. If anything changes, the old button stops working.

  • Demo approvals are simulated, signed clicks on synthetic data. They are not permission to touch a real CRM or send anything.

Quick start

python3 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
python run_demo.py          # full scenario, writes outputs/
python run_evals.py         # evaluation report, writes evals/report.md
python -m unittest discover -s tests -t .

No API key needed. See SETUP.md for Claude, Slack and Claude Code setup.

Example output

From python run_demo.py (synthetic accounts):

Approval clicks
  sales manager approves a lifecycle change      C-1001  denied    approver_lacks_permission:lifecyclestage
  RevOps admin approves                          C-1001  approved  recorded
  forged signature                               C-1003  denied    bad_signature
  button from an older draft (hash mismatch)     C-1003  denied    hash_mismatch
Writes
  crash after property write                     P-C-1001-3f5cfea6    crashed  left APPLYING
  resume after crash                             P-C-1001-3f5cfea6    applied  ok
  record edited after approval                   P-C-1005-c6bae183    stale    stale_record

Evaluation (measured locally, synthetic data)

python run_evals.py scores 24 hand-labelled accounts (34 signals) and an 18-scenario attack and failure suite, against the same keyword rules without guardrails:

Measure

Baseline

This agent

Play accuracy

0.75

0.875

Injection signals caught

0 of 6

5 of 6

Injected text reaching a proposal

6

1

Emails reaching a proposal

1

0

Unsafe writes, 13 attack scenarios

11 (gate that only checks for a click)

0

The injection that gets through is a paraphrase held out on purpose. This is my own small labelled set, not production data. Full report: evals/report.md.

How this runs today (and what production would add)

Implemented and tested locally: MCP server (in-memory and stdio), approval gate, Slack signature handling, executor, audit log and evals. Implemented but not tested against a live workspace: Slack posting with --live-slack. Not built: a real HubSpot client, queue workers and hosting. See docs/DETAILS.md.

More

Related MCP Connectors

Related MCP Servers

  • A
    license
    B
    quality
    D
    maintenance
    Enables AI assistants to interact with a HubSpot CRM account via natural language, starting with read-only lookups and optionally enabling write operations like creating contacts, deals, and notes.
    11
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    Exposes CRM tools from HubSpot to Claude and other agents, enabling pipeline analysis, deal risk detection, and automated follow-up drafting.
    632 npm
    MIT
  • A
    license
    A
    quality
    C
    maintenance
    Enables Claude to search, create, and update contacts, deals, and support tickets in HubSpot, and to generate cross-object account summaries.
    10
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    Connects AI assistants to your workspace so you can build audiences from connected HubSpot lists, author and publish outreach flows, enroll selected contacts, and review team tasks in natural language. Every email and call action requires human approval before it executes.
    Apache 2.0