Announcing CIMD support for MCP Client registration
Learn more

Salesloft MCP vs Salesloft API for AI Agents (2026)

TL;DR

  • The Salesloft MCP Server is gated behind the Salesloft Agentic add-on and enabled per user by a workspace admin. It is documented in Salesloft's help center as an end-user feature, not on the developer portal as a platform surface. There is no published developer-facing auth spec, tool schema list, or versioning contract for it.
  • Salesloft's own July 2026 announcement lists write-back, Cadence and activity data, and Clari Copilot call intelligence as capabilities rolling out through late summer 2026. If your agent needs to take actions inside Salesloft today, verify what your workspace actually exposes before you design around it.
  • The REST API accepts three credential types: OAuth Authorization Code for per-user delegation, OAuth Client Credentials for server-to-server work with no user present, and customer API keys. Partners cannot ship on API keys; Salesloft rejects partner applications that use them.
  • Salesloft access tokens expire in 7,200 seconds and refresh tokens rotate on every use, with all previous refresh tokens revoked. Two agent threads refreshing the same rep's token concurrently is a live production failure mode, not a theoretical one.
  • Scalekit's Salesloft connector handles the per-rep OAuth flow, vaulted token storage, and rotation for both paths, so the MCP versus API decision does not change what you build at the credential layer.

Your agent needs to read and write Salesloft: pull cadence steps, find prospects who opened but never replied, log call outcomes, enroll people into the right sequence. Salesloft now ships two paths to that data. There is a Salesloft MCP Server that launched in April 2026 and is natively listed in Claude's connector directory, and there is the v2 REST API that integrations have been building against for years. They are not interchangeable. They differ on capability coverage, on which auth flows they accept, and on who owns the credential lifecycle in production. Here's how to pick.

What Salesloft MCP and Salesloft API actually are

These are two different products with two different audiences. One is a feature sold to revenue teams; the other is a platform surface sold to developers and partners. That distinction drives most of what follows.

The Salesloft MCP Server

Salesloft shipped its MCP Server in the April 2026 release, describing it as a way for AI tools to pull live data directly from Salesloft so answers reflect actual pipeline, calls, and accounts. Availability is limited to users with the Salesloft Agentic add-on, and a workspace admin has to enable it per user. Setup is documented in the Salesloft MCP Server help article.

In July 2026, Clari and Salesloft announced an expansion that puts Salesloft natively in Claude's connector directory and adds Cadence and activity data, Clari Copilot call intelligence, forecasting data, and write-back capabilities on a rollout running through late summer 2026.

The Salesloft REST API

The Salesloft platform API is a versioned REST interface at api.salesloft.com/v2 covering people, accounts, cadences, cadence memberships, actions, tasks, notes, calls, emails, email templates, and users. The full endpoint reference is published on the developer portal.

Authentication accepts a bearer token from any of three sources: the Authorization Code flow, the Client Credentials flow, or a customer API key. The API also exposes webhook subscriptions so a service can react to changes rather than poll for them.

Comparing them where it matters for agents

Four dimensions decide this for an agent builder: what the agent can do, what credential it can hold, what you own when things break, and which scenario you are actually building for.

What your agent can actually do

Salesloft has not published an MCP tool inventory or schema reference on its developer portal. That absence is itself the finding. The table below reflects what Salesloft has stated publicly, and marks anything it has not documented rather than guessing.

Capability
Salesloft MCP Server
Salesloft REST API
Read pipeline, account, and activity context
Yes
Yes, across v2 endpoints
Cadence and activity data exposure
Rolling out through late summer 2026
Yes
Write-back into Salesloft records
Rolling out through late summer 2026
Yes
Delete people, accounts, notes, tasks
Not publicly documented
Yes
Webhook event subscriptions
No
Yes
High-volume paginated reads
Not publicly documented
Yes, subject to page cost
Server-to-server auth with no user present
No
Yes, Client Credentials
Static credential auth
No
Yes, customer API keys
Published tool or endpoint schema reference
No
Yes, on the developer portal
Explicit version contract
No
Yes, v2
Requires a paid add-on
Yes, Salesloft Agentic
No
Native listing in Claude's connector directory
Yes
Not applicable

Where the MCP ceiling sits for agent builders

The Salesloft MCP Server is built for a rep sitting in Claude asking about their own pipeline. That is a legitimate and well-served use case. It is a different thing from a platform surface you architect a multi-tenant product on top of.

Three gaps matter concretely. There is no event subscription surface, so an agent that reacts to a reply, a bounce, or a cadence completion has to poll or use API webhooks. There is no published schema contract, so an agent bound to specific tool signatures can break when Salesloft ships a server update. And the write-back rollout is in flight, so a capability you validate this week may behave differently next month.

The auth path each one puts you on

The MCP Server's access model is administrative: an admin turns it on for a rep, the rep connects through their AI client, and the connection carries that rep's identity. That is architecturally correct for user-present work and a hard stop for anything headless.

The REST API gives you three distinct credential shapes:

  • OAuth Authorization Code: one grant per rep, scoped to what that rep can see and do. This is the right model for multi-tenant B2B agents and the only path Salesloft approves for partner applications.
  • OAuth Client Credentials: server-to-server, no user in the loop, no browser redirect. Correct for nightly syncs and scheduled pipelines. Note that this flow returns no refresh token.
  • Customer API keys: a static ak_ bearer token tied to the issuing user. Practical for internal tooling. Salesloft explicitly will not approve partner applications built on API keys.

What token rotation actually costs you

This is the detail that surfaces at three months, not at demo time. Salesloft access tokens carry an expires_in of 7200 seconds. When you exchange a refresh token, Salesloft revokes every previous refresh token for that grant and issues a new one you must persist.

That makes concurrent refresh a correctness problem rather than a performance one. Two agent workers handling the same rep at the same moment will both attempt a refresh, one will win, and the loser's stored refresh token is now dead. The rep gets silently disconnected and nobody finds out until a scheduled run returns nothing. Handling this correctly requires distributed locking around refresh, proactive renewal against expires_in, and atomic write-back of the rotated token.

What you own in production

On the MCP path, Salesloft manages hosting, schemas, and permission enforcement. You still own per-rep connection state, detecting when an admin disables the add-on for someone, and adapting when tool behavior changes underneath you without a version bump.

On the REST path you own endpoint selection, request construction, pagination, retry logic, and the full token lifecycle described above. That is more surface area and considerably more control. You pin to v2, you migrate on your schedule, and a Salesloft server-side change to an AI feature does not restructure the contract your pipeline depends on.

Rate limits are a team-level budget, not a per-agent one

Salesloft's rate limit is 600 cost per minute, applied at the team level rather than per integration. Every integration your customer runs draws from the same budget, including yours.

Deep pagination is penalized on a sliding scale: pages 101 to 150 cost 3 points, 151 to 250 cost 8, 251 to 500 cost 10, and 501 and above cost 30. Salesloft's guidance is to build a cursor poller keyed on updated_at instead of walking page numbers. Responses carry x-ratelimit-endpoint-cost and x-ratelimit-remaining-minute, and an agent doing real work should read both. Agentic workflows fan out into multiple sequential calls per user action, so the math moves faster than it does for a traditional integration.

When to use MCP, when to use the API

Two lists, both specific to Salesloft rather than generic MCP advice.

Use the Salesloft MCP Server when:

  • Your reps already have the Salesloft Agentic add-on and want pipeline context inside Claude without you building anything
  • The work is read-first: call prep, account briefings, "who is overdue and has not replied" questions asked conversationally
  • You want Salesloft's own permission model and admin gating to constrain access, and you are comfortable with an admin sitting in the enablement path
  • You are validating whether a Salesloft agent is useful before committing engineering time to it

Use the Salesloft REST API when:

  • Your agent runs headless: overnight cadence hygiene, scheduled activity logging, pipeline digests, engagement scoring pipelines
  • Your agent must react to Salesloft events through webhook subscriptions rather than polling
  • You are building a multi-tenant B2B product where every customer workspace needs its own credential and its own revocation boundary
  • You need write coverage today across people, accounts, cadence memberships, tasks, and notes rather than tracking a rollout
  • Deterministic behavior matters and an unannounced schema change would be an incident

The credential problem that exists on both paths

Both paths hand you a credential per rep. Neither hands you a vault, rotation logic, or a revocation flow. That infrastructure gets built regardless of which path you chose.

The N-credential math for a sales engagement agent

A sales engagement agent is per-rep by nature. Cadence ownership, activity attribution, and manager visibility all depend on the action being recorded under the rep who triggered it. Run that agent for 60 reps across 12 customer workspaces and you have 60 OAuth grants to store encrypted, 60 access tokens expiring on a two-hour clock, and 60 rotating refresh tokens that must be written back atomically.

Then a rep leaves. Their Salesloft access is disabled, but a stored refresh token in your database does not know that. A scheduled agent does not decide to stop using it. It just keeps trying, and the failure is a silent 401 in a background job rather than an alert. This is exactly the kind of scenario covered in detail when examining credential ownership across agent tool-calling patterns.

The shared token failure mode

A single service-account token is the shortcut everyone reaches for, and it looks correct in a demo. In production it collapses attribution. Every logged call, every note, every cadence enrollment appears under one identity. Manager dashboards break, activity reporting breaks, and the audit trail cannot answer which human initiated a given action.

Where Scalekit fits

Scalekit's Salesloft connector runs the per-rep OAuth flow, holds each rep's tokens in an AES-256 vault namespaced per tenant, and resolves the correct credential server-side on every tool call. Refresh and rotation are handled for you, which removes the concurrent-refresh race entirely. The credentials never enter your agent runtime or the LLM context. The MCP versus API decision does not change any of that. For a deeper look at why building this yourself carries hidden costs, see the hidden cost of building OAuth internally for AI agents.

Building a Salesloft agent with Scalekit

Scalekit ships one Salesloft connector rather than separate API and MCP variants. The same connector is callable as native tool schemas through execute_tool and reachable over a Scalekit-hosted MCP endpoint at https://mcp.scalekit.com/salesloft. You pick the interface; the auth model is identical either way.

What the connector exposes

The connector ships 36 prebuilt tools spanning the objects a sales engagement agent actually touches: accounts, people, cadences, cadence memberships, actions, tasks, notes, calls, emails, email templates, and users. Each ships with an LLM-ready schema tested against the live API, including the filter surface that makes these tools useful.

salesloft_people_list alone accepts 53 parameters covering cadence membership, reply state, bounce state, contact restrictions, owner, stage, and timestamp windows. Writing and maintaining that schema yourself is the hidden tax. Writing the schema is the hard part, not the API call.

Configure the connection once

Create a Salesloft OAuth application under Settings then Your Applications then OAuth Applications, and register its client ID and secret in the Scalekit dashboard under AgentKit then Connections. Note the connection name you create; the string must match the connection_name in your code exactly. This is the single most common integration error.

pip install scalekit anthropic npm install @scalekit-sdk/node @anthropic-ai/sdk

Authorize a rep

Each rep authorizes once. Scalekit creates a connected account tied to your application's identifier for that person and tracks its auth state from then on.

import os import scalekit.client scalekit_client = scalekit.client.ScalekitClient( client_id=os.getenv("SCALEKIT_CLIENT_ID"), client_secret=os.getenv("SCALEKIT_CLIENT_SECRET"), env_url=os.getenv("SCALEKIT_ENV_URL"), ) actions = scalekit_client.actions IDENTIFIER = "rep_4471" # your app's stable ID for this sales rep CONNECTION_NAME = "salesloft" # must match the connection name in the Scalekit dashboard account = actions.get_or_create_connected_account( connection_name=CONNECTION_NAME, identifier=IDENTIFIER, ) if account.connected_account.status != "ACTIVE": magic_link = actions.get_authorization_link( connection_name=CONNECTION_NAME, identifier=IDENTIFIER, ) print("Authorize Salesloft:", magic_link.link)

Retrieve the rep's authorized tool surface

Before the agent loop runs, retrieve the tools this rep's connected account is authorized to call. This is not a catalog browse. The surface returned is derived from what this specific rep authorized, so a rep without write scope never sees a write tool in context, and the model cannot select what it cannot see.

from google.protobuf.json_format import MessageToDict scoped_response, _ = actions.tools.list_scoped_tools( identifier=IDENTIFIER, filter={"connection_names": [CONNECTION_NAME]}, page_size=100, ) llm_tools = [ { "name": MessageToDict(t.tool).get("definition", {}).get("name"), "description": MessageToDict(t.tool).get("definition", {}).get("description", ""), "input_schema": MessageToDict(t.tool).get("definition", {}).get("input_schema", {}), } for t in scoped_response.tools ]

Run the agent loop with the Claude SDK

Scalekit returns input_schema in exactly the shape Anthropic's tool use API expects, so nothing needs reshaping. The loop below is complete.

import anthropic client = anthropic.Anthropic() messages = [{ "role": "user", "content": ( "Find people currently on a cadence who opened an email in the last 7 days " "but have not replied, and log a note on each one flagging them for a call." ), }] while True: response = client.messages.create( model="claude-sonnet-4-6", max_tokens=2048, tools=llm_tools, messages=messages, ) if response.stop_reason == "end_turn": print(response.content[0].text) break tool_results = [] for block in response.content: if block.type == "tool_use": result = actions.execute_tool( tool_name=block.name, identifier=IDENTIFIER, tool_input=block.input, ) tool_results.append({ "type": "tool_result", "tool_use_id": block.id, "content": str(result.data), }) messages.append({"role": "assistant", "content": response.content}) messages.append({"role": "user", "content": tool_results})

The same loop in TypeScript

Identical model, Node SDK. Note that tool listing lives on scalekit.tools while execution lives on scalekit.actions.

import { ScalekitClient } from '@scalekit-sdk/node'; import { ConnectorStatus } from '@scalekit-sdk/node/lib/pkg/grpc/scalekit/v1/connected_accounts/connected_accounts_pb'; import Anthropic from '@anthropic-ai/sdk'; const scalekit = new ScalekitClient( process.env.SCALEKIT_ENV_URL!, process.env.SCALEKIT_CLIENT_ID!, process.env.SCALEKIT_CLIENT_SECRET!, ); const anthropic = new Anthropic(); const identifier = 'rep_4471'; const connectionName = 'salesloft'; // must match the Scalekit dashboard connection name const { connectedAccount } = await scalekit.actions.getOrCreateConnectedAccount({ connectionName, identifier, }); if (connectedAccount?.status !== ConnectorStatus.ACTIVE) { const { link } = await scalekit.actions.getAuthorizationLink({ connectionName, identifier }); console.log('Authorize Salesloft:', link); } const { tools } = await scalekit.tools.listScopedTools(identifier, { filter: { connectionNames: [connectionName] }, pageSize: 100, }); const llmTools = tools.map(t => ({ name: t.tool.definition.name, description: t.tool.definition.description, input_schema: t.tool.definition.input_schema, })); const messages: Anthropic.MessageParam[] = [ { role: 'user', content: 'Which prospects in my enterprise cadence are overdue on step 4 with no reply?' }, ]; while (true) { const response = await anthropic.messages.create({ model: 'claude-sonnet-4-6', max_tokens: 2048, tools: llmTools, messages, }); if (response.stop_reason === 'end_turn') { const text = response.content.find(b => b.type === 'text'); if (text?.type === 'text') console.log(text.text); break; } const toolResults: Anthropic.ToolResultBlockParam[] = []; for (const block of response.content) { if (block.type === 'tool_use') { const result = await scalekit.actions.executeTool({ toolName: block.name, identifier, toolInput: block.input as Record, }); toolResults.push({ type: 'tool_result', tool_use_id: block.id, content: JSON.stringify(result.data), }); } } messages.push({ role: 'assistant', content: response.content }); messages.push({ role: 'user', content: toolResults }); }

LangChain, if that is your runtime

Scalekit returns native StructuredTool objects, so there is no adapter layer to write. For more on how LangChain tool calling works in agentic contexts, see LangChain tool calling: how it works, where it stops, and how Scalekit completes it.

from langchain_openai import ChatOpenAI from langchain_core.messages import HumanMessage, ToolMessage tools = actions.langchain.get_tools( identifier="rep_4471", connection_names=["salesloft"], page_size=100, ) tool_map = {t.name: t for t in tools} llm = ChatOpenAI(model="gpt-4o").bind_tools(tools) messages = [HumanMessage("Enroll every person at Meridian with no active cadence into cadence 8814.")] while True: response = llm.invoke(messages) messages.append(response) if not response.tool_calls: print(response.content) break for tc in response.tool_calls: result = tool_map[tc["name"]].invoke(tc["args"]) messages.append(ToolMessage(content=str(result), tool_call_id=tc["id"]))

Scoping the tool surface with a Virtual MCP server

Handing an agent all 36 Salesloft tools is a mistake in two directions at once. At roughly 200 tokens per tool schema, the full surface burns around 7,200 tokens of context before the agent does any work, and at thousands of runs per day that is a real operating cost. Selection accuracy degrades at the same time, because the model is choosing from a decision space it was never designed to handle at that scale.

Virtual MCP Servers fix both by declaring exactly which tools an agent role can see. The fix is not better prompting. It is surface reduction.

Define the server once per agent role

A cadence hygiene agent needs four tools, not thirty-six. Create the server once and reuse the static mcp_server_url for every rep.

import os from scalekit import ScalekitClient from scalekit.actions.models.mcp_config import McpConfigConnectionToolMapping scalekit_client = ScalekitClient( env_url=os.environ["SCALEKIT_ENV_URL"], client_id=os.environ["SCALEKIT_CLIENT_ID"], client_secret=os.environ["SCALEKIT_CLIENT_SECRET"], ) vmcp_response = scalekit_client.actions.mcp.create_config( name="cadence-hygiene-agent", connection_tool_mappings=[ McpConfigConnectionToolMapping( connection_name="salesloft", tools=[ "salesloft_people_list", "salesloft_cadence_memberships_list", "salesloft_cadence_memberships_delete", "salesloft_notes_create", ], ), ], ) config_id = vmcp_response.config.id mcp_server_url = vmcp_response.config.mcp_server_url

Four tools instead of thirty-six drops schema overhead by roughly 89 percent. It also means this agent structurally cannot delete a person or create an account, because those tools are not on its endpoint.

Mint a session token per run

The endpoint is static. The identity is not. Confirm the rep's connection is still live, then mint a short-lived token scoped to that rep before every run.

from datetime import timedelta accounts_response = scalekit_client.actions.mcp.list_mcp_connected_accounts( config_id=config_id, identifier="rep_4471", include_auth_link=True, ) for account in accounts_response.connected_accounts: if account.connected_account_status != "ACTIVE": raise RuntimeError( f"{account.connection_name} needs auth: {account.authentication_link}" ) token_response = scalekit_client.actions.mcp.create_session_token( mcp_config_id=config_id, identifier="rep_4471", expiry=timedelta(minutes=30), ) mcp_server = { "url": mcp_server_url, "headers": {"Authorization": f"Bearer {token_response.token}"}, }

Why this matters for multi-tool, multi-tenant agents

Real sales agents rarely stop at Salesloft. A deal intelligence agent reads Salesloft cadence execution, pulls call context from Gong, and writes back to Salesforce. Each of those connectors adds its own tool surface, and the combined catalog crosses a hundred tools quickly.

One Virtual MCP server definition covers all of them with the specific tools each agent role needs, and one session token per run resolves every connector under the same rep. No credential sharing between reps, no per-rep server configuration, and no MCP server for you to deploy, host, or maintain. Cross-tenant tool calling requires per-tenant authorization, and there is no shortcut around that. For a concrete example of this pattern in practice, see how to build a deal intelligence agent with Gong, Attio, and Slack.

Observability: auth logs for downstream tool calls

Salesloft's own API Logs show you which integration hit which endpoint on a given team. What they cannot tell you is which human triggered a given agent run, or which agent role in your product made the call.

What you get per tool call

Scalekit logs every downstream tool call: which rep's connected account resolved, which tool ran, what came back, and when. History is retained for 90 days and is exportable to a SIEM. Auth logs cover the credential side of the same trail, including token issuance, refresh, and revocation events, with filtering by user, organization, and status.

Why the correlation matters

When a compliance reviewer asks whether the agent was authorized to remove a person from a cadence last Tuesday, the answer needs three facts in one place: who authorized the connected account, what scope it carried at execution time, and what the tool actually did. Standard application logging captures a user ID and a timestamp and none of the rest.

Failure-first visibility matters just as much. A rep who revokes Salesloft access fails closed on the next tool call, that event is logged, and other reps on the same connection are unaffected. That is the difference between noticing a broken integration and discovering it in a quarterly pipeline review. For a structured approach to this problem, see agent tool observability: your agent is running — is it actually working?

Which one to build against

The decision comes down to who is present when the agent runs.

If your agent is rep-facing

If reps already have the Salesloft Agentic add-on and the job is call prep, account briefings, and pipeline questions answered in natural language, the Salesloft MCP Server gets there with no code from you. Treat it as a feature your customers turn on, not as a platform you build a product on.

If your agent is headless or multi-tenant

If the agent runs on a schedule, reacts to webhook events, or acts across multiple customer workspaces with independent revocation boundaries, build against the REST API. Client Credentials for service-level work, Authorization Code per rep for anything attributed to a human, and a real cursor poller instead of deep pagination.

Most production Salesloft agents end up running both modes in the same product. The interactive assistant sits on one path, the overnight pipeline on the other. What does not change across that split is the credential layer: 60 reps still means 60 rotating grants, and that is the part that needs production-grade infrastructure rather than a database column. The patterns that emerge when moving from single-tenant to multi-tenant are worth studying before you commit to an architecture — see how tool calling auth changes when you move from single-tenant to multi-tenant.

Talk to other Salesloft agent builders

If you are working through cadence attribution, per-rep scoping, or the refresh rotation race, other people are solving the same problems right now.

Join the Scalekit Slack community to compare notes, or talk to an engineer if you want help on a specific architecture decision.

Browse the Scalekit Salesloft connector: scalekit.com/connectors/salesloft

No items found.
Agent
Auth Quickstart
On this page
Share this article
Agent
Auth Quickstart

Acquire enterprise customers with
zero upfront cost.

Every feature unlocked. No hidden fees.