Guide · CRM
HubSpot and Salesforce MCP for sales teams: let an agent update your CRM, with approvals
To let an AI agent update HubSpot or Salesforce without handing it the whole CRM, connect the CRM to actionlake, an MCP gateway, once, then give each rep's agent a key that can read the CRM and log notes freely, while deal-stage and amount changes wait for a sales manager's approval. The agent works through one remote MCP server, https://connect.actionlake.com/mcp, never sees the CRM token, and every change is recorded with its reason.
What sales teams actually want an agent to do
| Job | Example request | Effect |
|---|---|---|
| Prepare for a call | "What do we know about Acme, and what happened last quarter?" | Read |
| Log the call | "Add a note to Jane Smith: wants pricing for 40 seats, follow up Friday." | Write, low risk |
| Clean records | "Fix the job titles on these five contacts." | Write |
| Move the pipeline | "Move the Acme deal to Contract sent, amount 48,000." | Write, forecast-changing |
| Bulk changes | "Archive every lead with no activity in a year." | Destructive |
The first two should happen at once. The last two are what a sales manager wants to see before they happen. That split is the design below.
The connectors
| Connector | Covers | Example actions |
|---|---|---|
| HubSpot CRM | Contacts, companies, notes | hubspot_crm.contacts.search, hubspot_crm.contacts.update, hubspot_crm.notes.create |
| HubSpot Deals | Deals, pipelines, stages | hubspot_deals.deals.search, hubspot_deals.deals.update, hubspot_deals.pipeline_stages.list |
| HubSpot Tickets | Support tickets | Ticket reads and updates |
| Salesforce Sales Cloud | Accounts, contacts, leads, opportunities, tasks, SOQL | salesforce_sobjects.opportunities.update, salesforce_sobjects.tasks.create, salesforce_sobjects.query.run |
| Salesforce Service Cloud | Cases and service objects | Case reads and updates |
Contact listing answers to one shared name, crm.contact.list, across 34 connectors, so the same agent instructions work on whichever CRM is connected. See canonical action names.
HubSpot and Salesforce each offer MCP access of their own. HubSpot's remote MCP server, at https://mcp.hubspot.com, has been generally available since 13 April 2026: each user signs in with OAuth 2.1 and PKCE, and every action respects that user's HubSpot permissions (HubSpot developer changelog, checked 22 October 2026). If you need one CRM in one client with the vendor's permissions, that may be enough. A gateway adds per-agent keys, caps, approval rules, one ledger, and questions that join the CRM with billing or support.
Step 1: Connect the CRM once
Both CRMs use OAuth. Create an app in the CRM (a HubSpot app with OAuth, or a Salesforce connected app), authorise it once as an admin, and store the resulting tokens with the app's client id and secret. actionlake renews the access token from the refresh token as it expires.
{
"op": "connections.create",
"service": "salesforce_sobjects",
"name": "default",
"secrets": { "access_token": "…", "refresh_token": "…", "client_id": "…", "client_secret": "…" },
"setup_data": { "instance_host": "https://yourcompany.my.salesforce.com" }
}
For HubSpot the shape is the same, with "service": "hubspot_crm" (and again for hubspot_deals) and no setup_data. Ask connections.requirements first; it returns the exact fields each service needs, free. Tokens are sealed on arrival and never returned.
The app's OAuth scopes are the outer limit. Grant the CRM app only the objects your agents need; actionlake's keys narrow it further, never wider.
Step 2: A key per rep, with deal changes gated
Mint keys in the console or with your root key over REST. Keys are never minted through an OAuth connection.
{
"name": "rep-agent-jordan",
"holder": "agent",
"allowed_actions": [
"hubspot_crm.read:*", "hubspot_deals.read:*",
"hubspot_crm.notes.create", "hubspot_crm.contacts.update",
"hubspot_deals.deals.update"
],
"cap_calls": 2000,
"confirm_policy": "human",
"approver": "[email protected]",
"approval_rules": [
{ "match": "hubspot_deals.deals.update", "approver": "[email protected]" }
]
}
What this key does:
- Reads anything in HubSpot CRM and Deals, at once.
- Notes and contact fixes go straight in. They are writes, so they are recorded, but nobody waits.
- Deal updates wait. The sales manager gets an email with a signed link, or decides in the console. The update runs when they approve; a decline stops it.
- Archiving is not in
allowed_actions, so it is refused. If you add it, it is a destructive action: underconfirm_policy: humanit needs a person's approval, and the agent cannot confirm it itself.
For Salesforce, the same pattern uses salesforce_sobjects.read:*, salesforce_sobjects.tasks.create and a rule on salesforce_sobjects.opportunities.update.
Step 3: What the rep's agent sends
The rep says: "Move the Acme deal to Contract sent, 48,000." The agent first reads the pipeline's stages, because HubSpot wants the internal stage id, not its label. Then:
{
"action": "hubspot_deals.deals.update",
"input": { "record_id": "18734420115", "stage": "contractsent", "amount": "48000" },
"intent": "Jordan asked to move the Acme deal to Contract sent at 48,000 after today's call."
}
The call is parked, not refused. The reply names the approval it is waiting on. When the manager approves, the update runs and the run records who approved it. The intent sentence is what the manager reads in the approval mail, so the agent's reason travels with the request.
Before anything runs: check
For bulk or unfamiliar changes, the agent sends the same payload to check first. It validates the input against HubSpot's or Salesforce's schema as the connector describes it, confirms the key may run it, and says it will need an approval and roughly what it will cost. It is free and sends nothing. See dry run.
Questions across the CRM and other systems
A sales question often needs another system. With ask, the agent fetches from both and joins on the company, and only the answer returns:
- "Which customers in our pipeline are overdue on invoices?" HubSpot companies with Xero or QuickBooks Online.
- "Which accounts up for renewal have open support tickets?" Salesforce accounts with your help desk.
See cross-system questions for how the join matches companies.
A rollout that keeps the forecast clean
| Week | Key change | What you learn |
|---|---|---|
| 1 | Reads only: hubspot_crm.read:*, hubspot_deals.read:* | Which questions reps actually ask |
| 2 | Add hubspot_crm.notes.create | Whether call notes improve, and how many calls it takes |
| 3 | Add hubspot_deals.deals.update behind an approval rule | How often the manager approves as sent |
| 4 | Keep the rule on amounts and stages; drop it on fields managers always approve | Where approval adds value, and where it only adds delay |
Each step is a keys.update on the rep's key. Nothing about the CRM connection changes, and no rep loses access while you adjust.
What it costs
Each request sent to HubSpot or Salesforce that returns an answer is one upstream call. Searches for actions, schema reads, check, cache hits and failures you did not cause (a 401, 403, 429, 5xx or a timeout) are free. A request the CRM rejects as invalid, such as a 400 or 404, is billed. Free includes 100,000 calls a month; Starter is US$49 a month for 250,000. A rep's agent doing call prep and logging typically makes a handful of calls per request. See pricing.
Frequently asked questions
Can the agent see every record in the CRM?
It sees what the CRM app's OAuth scopes and its actionlake key both allow. Narrow the app's scopes in HubSpot or Salesforce, and narrow the key to the objects and actions each agent needs.
Who approves, and how fast?
The person named on the rule, or the key's approver, or the tenant's default approver. They get an email with a signed, single-click link and can also decide in the console. The run waits until they decide.
Will the agent create duplicate contacts?
It can only create contacts if its key allows hubspot_crm.contacts.create. Writes are never retried automatically, so a timeout does not produce a second record. Ask the agent to search before it creates; HubSpot dedupes contacts on email.
Can I see what each rep's agent changed?
Yes. Every call is a row in the ledger with the key, action, connection, outcome, cost and the agent's intent, chained with SHA-256 and sealed daily. See AI agent audit logs.
Try it on your own systems.
100,000 free calls a month. No card. Hard caps on every key.