Announcing CIMD support for MCP Client registration
Learn more

Outreach MCP vs Outreach API for AI Agents (2026)

Nityashree Yadunath
Product Marketing Manager

TL;DR

  • Outreach MCP exposes 32 tools covering search, retrieval, record creation, deletion, and sequence enrollment. It has no update tools at all; Outreach made that an explicit product decision. Tasks, templates, call logging, mailboxes, webhooks, bulk actions, and custom objects are REST-only.
  • MCP auth is OAuth 2.1 with PKCE and Dynamic Client Registration, and nothing else. Client credential authentication is explicitly unsupported, and every connecting identity must be an active, licensed Outreach seat with the Amplify add-on enabled at the org level.
  • The REST API supports OAuth 2.0 plus an S2S token flow that authenticates your application rather than a user. S2S is the only non-interactive credential path, and it is deliberately narrow: no user identity, a restricted scope list, and some write operations that will not work at all.
  • Outreach access tokens live 2 hours and refresh tokens live 14 days with rotation on every use. An agent that sits idle for two weeks loses its connection entirely and needs the user back in a browser. This is a lifecycle problem, not a bug.
  • Both paths hand you one credential per user and neither stores, rotates, or revokes it. The Scalekit Outreach connector handles the OAuth flow, vaulted per-user tokens, and refresh for both paths, so the MCP vs API decision does not change your auth infrastructure.

Your agent needs to work with Outreach. It needs to find prospects, check which sequences a deal owner is running, pull the Kaia transcript from last week's call, and log what happened next. Outreach ships two paths: a hosted MCP server at api.outreach.io/mcp and a REST API that has been in production for years. They cover overlapping but genuinely different ground, they put you on different auth paths, and for one very common class of agent, the MCP path has a hard architectural stop. Here is how to pick.

What Outreach MCP and Outreach API actually are

Two different objects with two different design intents. One was built for a seller talking to an LLM. The other was built for systems integration. Reading them as interchangeable transports for the same capability set is the mistake that costs you a rewrite.

The Outreach MCP Server

Outreach announced general availability of its MCP Server in February 2026. It is a hosted, Outreach-maintained endpoint at https://api.outreach.io/mcp, speaking Streamable HTTP and implementing the Model Context Protocol (MCP) 2025-03-26 revision and above, including tool annotations and self-describing schemas via tools/list.

Two gates sit in front of it. The organization must have the Amplify add-on enabled with active credits, and an admin must toggle MCP Server on under Administration, Organization, Org Info, Gen AI. Create actions are on by default at that toggle; delete actions are off by default.

Official docs: Outreach MCP Server developer portal and the MCP Server overview in Outreach support.

The Outreach REST API

The REST API is a JSON:API-styled v2 surface at https://api.outreach.io/api/v2, covering prospects, accounts, opportunities, sequences, sequence states and steps, tasks, templates, snippets, mailings, mailboxes, calls, users, webhooks, batches, imports, and custom objects.

Authentication accepts an OAuth 2.0 bearer token obtained through the authorization code flow, with period-separated scopes such as prospects.read, accounts.write, and sequences.all. Scopes are not additive; prospects.write does not grant read. A separate S2S flow issues an application-scoped token for server contexts.

Official docs: Outreach REST API developer portal.

Comparing them where it matters for agents

Four dimensions decide this: what the agent can do, what credential it holds, what you operate, and which one wins for your specific workload.

What your agent can actually do

The MCP tool catalog breaks into 21 read and discovery tools, 8 write and mutation tools, and 3 schema and special tools. The read surface is strong. The write surface is deliberately small.

Capability
Outreach MCP Server
Outreach REST API
Search prospects, accounts, opportunities
Yes
Yes
Fetch a single record by ID
Yes
Yes
Lookup by external CRM ID
Yes
Yes, via filters
Create prospects, accounts, opportunities
Yes, admin-toggled
Yes
Update an existing record
No
Yes
Delete records
Yes, off by default
Yes
Enroll or remove prospects from a sequence
Yes
Yes
Kaia meeting transcript search
Yes
Yes
AI meeting brief and record-level Q and A
Yes
Not exposed
Tasks, templates, snippets, mailboxes
No
Yes
Log a call record
No
Yes
Webhook subscriptions
No
Yes
Bulk actions, CSV imports, bulk upsert
No
Yes
Custom objects
No
Yes

The missing verb nobody expects

The single most consequential gap is that Outreach MCP has no update tools. Not for prospects, not for accounts, not for opportunities. The catalog contains prospect_create and prospect_delete but no prospect_update.

This is not an oversight or a roadmap gap that closes next quarter. Outreach states the reasoning directly: internal testing showed LLMs behaving unpredictably when updating existing records, so they shipped read, create, and delete only. If your agent's job is to keep opportunity fields current or correct prospect data after a call, the MCP server structurally cannot do it. That work goes over REST.

The AI tools that only exist on MCP

The gap runs the other way too, and comparison posts usually miss this. Three MCP tools have no REST equivalent: account_answer_question, opportunity_answer_question, and prepare_for_meeting. These are Amplify intelligence features surfaced as tools, not thin wrappers over v2 endpoints.

If your agent's value is "brief me on this account before the call," MCP gives you that in one call. Rebuilding it over REST means assembling accounts, opportunities, mailings, and Kaia records yourself and doing your own synthesis.

The auth path each one puts you on

The MCP authentication model is OAuth 2.1 with PKCE, plus Dynamic Client Registration per RFC 7591. The client discovers .well-known/oauth-authorization-server, registers itself dynamically, and runs the user through an authorization code flow. Permissions inherit from the authenticated user's Outreach RBAC profile on every tool call.

That inheritance is architecturally correct. What the user cannot do, the agent cannot do. The constraint is what surrounds it.

Three requirements that disqualify some agent runtimes

Your MCP client itself must support OAuth 2.1 user authentication and Dynamic Client Registration. A bespoke agent runtime that speaks MCP but not DCR cannot connect. That is a client-side capability requirement, not a configuration flag.

Client credential authentication is explicitly not supported. Outreach enforces that an active user credential is presented, and if you use an agentic identity, that identity must be an active, licensed Outreach user consuming a seat.

Amplify gating means MCP availability is a commercial question before it is a technical one. If your B2B customers do not all carry Amplify, your MCP-based agent does not work for all of them.

Where the headless gap actually is

Be precise here, because the common framing is wrong. Outreach does support non-user identities over MCP as long as a valid token is provided and that identity maps to a licensed user. So a scheduled agent can technically run on MCP.

The problem is credential issuance. There is no non-interactive way to mint that token. Bootstrapping requires a browser, and re-bootstrapping requires it again whenever the grant lapses. Combine that with a 14-day refresh token and a nightly job becomes a recurring human dependency.

What S2S gives you, and what it does not

The REST API's S2S access flow is the genuine non-interactive path. You register public keys, sign an RS256 app token with your private key and S2S_GUID, exchange it plus an installation ID for a one-hour access token, and call the API. There is no refresh; you request a new token.

State the tradeoff plainly, because Outreach does. The S2S token carries no user identity, only your application's, scoped to one org installation. The available scope list is a subset of OAuth scopes. Some write operations need extra data such as an authorizer user ID, and some will not work at all. S2S is a real headless path, not a full-fidelity one.

Token lifetimes you have to design around

These numbers come from the Outreach API getting started guide and they shape your architecture more than the capability table does.

Property
Value
What it forces
Access token lifetime
2 hours
Proactive refresh, not 401-driven retry
Refresh token lifetime
14 days
Idle agents lose the grant entirely
Refresh token behavior
Rotates on every use
Store the newest, discard the previous
Token minting throttle
One per user per 60 seconds
Concurrent refresh needs distributed locking
Tokens per user and app pair
100 maximum
Do not mint per request
S2S token lifetime
1 hour, no refresh
Re-request on a timer

The 14-day figure is the one that surprises teams. A weekly pipeline hygiene agent is fine. A quarterly reporting agent is not; it will find a dead grant every single run.

Rate limits are shared, not additive

Outreach rate limits the API on a per-user basis at 10,000 requests per hour. Kaia recordings and transcripts carry tighter org-level limits: 3 calls per second and 6,000 calls per day.

MCP tool calls count against the same throttle. Choosing MCP does not buy you a second budget. Worse, MCP call volume is non-deterministic; Outreach notes a single natural-language query may fan out into five or more tool calls depending on how the model reasons. A Kaia-heavy research agent can exhaust a shared org-level daily ceiling on behalf of a handful of users.

What you own in production

On the MCP path, Outreach owns hosting, tool schemas, and permission enforcement. You own per-user token storage, refresh, tenant isolation, and the Amplify entitlement check before you promise a customer the feature works.

On the REST path, you own all of that plus endpoint selection, JSON:API request construction, the newFilterSyntax filter semantics, pagination, retry logic, and adapter code per resource. More surface area, more control, and a versioned contract that does not shift when a vendor updates a tool schema.

Schema stability cuts differently on each path

MCP tool schemas change when Outreach updates the hosted server, and Outreach says outright that it is continuously adding tools and that you should refresh periodically. The catalog already moved from 27 documented tools in the support article to 32 in the developer portal.

For an interactive assistant, that is upside; new capability arrives without a redeploy. For a deterministic pipeline where an unplanned schema change is an incident, it is a dependency you did not choose.

When to use MCP, when to use the API

Use Outreach MCP when:

  • Your agent is interactive and user-present: a rep asking for account context inside Claude, ChatGPT, or your own chat surface where the OAuth consent screen is natural
  • The core job is retrieval and briefing, and you want prepare_for_meeting and the *_answer_question tools rather than rebuilding synthesis over raw records
  • Your customer base reliably has Amplify, and every agent identity can hold a licensed Outreach seat
  • You want Outreach's RBAC profile enforcement as your authorization layer instead of building tool-level policy yourself

Use the Outreach REST API when:

  • Your agent updates existing records: opportunity fields, prospect corrections, task state, sequence configuration. MCP cannot do this at all
  • Your agent runs on a schedule with no user present, and you need the S2S flow or a managed refresh loop rather than a browser
  • You need tasks, templates, call logging, mailboxes, or custom objects, none of which exist as MCP tools
  • You need webhooks to react to sequenceState.finished, mailing.replied, or task.completed rather than polling
  • You are moving volume, where bulk actions and imports handle up to 100,000 items per request against a 5 million record daily org ceiling

The credential problem that exists on both paths

Both paths end at the same place: one Outreach credential per user, sitting somewhere in your infrastructure, silently aging.

The N-credential math for a sales engagement agent

A revenue agent serving 60 reps across 9 customer orgs is 60 OAuth grants. Each needs encryption at rest, per-tenant isolation, proactive refresh inside a 2-hour window, and rotation handling that stores the newest refresh token and drops the old one. Miss the 14-day window on any of them and that rep's agent goes dark.

Neither path gives you a vault, rotation logic, or a revocation flow. The token type differs. The infrastructure you must build does not. For a deeper look at secure token management for AI agents at scale, the patterns that apply here are the same ones production teams reach for regardless of which Outreach path they chose.

Revocation is somebody else's dashboard

Ask the offboarding question. When a rep leaves, can you revoke their agent's Outreach access?

On the MCP path, Outreach's answer is that you cannot do it through Outreach if you use a third-party identity provider; an admin revokes at the IdP. That is defensible security design and a genuine operational gap. Your application has no way to enumerate which agent grants were live at the moment of departure, and no way to invalidate one without touching the IdP.

Where Scalekit fits

Scalekit's Outreach connector resolves the per-user credential server-side on every tool call, so actions attribute to the rep who authorized them rather than a shared service account. Credentials never touch the agent runtime or the LLM context. The connector page documents an AES-256 vault namespaced per tenant, automatic refresh, and a 90-day audit trail. The same layer works whether you chose MCP or REST.

Building an Outreach agent with Scalekit

Scalekit ships a single Outreach connector, connection name outreach, authenticating over OAuth 2.0 and wrapping the REST surface. At the time of writing it publishes 53 tools, including the update operations the official MCP server does not expose.

Set up the connection and credentials

Create the connection in the dashboard under AgentKit > Connections. The connection_name string in your code must match the connection name configured there exactly; this is the single most common integration error.

pip install scalekit-sdk-python langchain-openai # .env SCALEKIT_ENV_URL=<your-environment-url> SCALEKIT_CLIENT_ID=<your-client-id> SCALEKIT_CLIENT_SECRET=<your-client-secret>

Authorize the rep once

The agent never sees an Outreach token. It references a connected account by your own user identifier, and Scalekit resolves the credential at call time.

import os from scalekit import ScalekitClient scalekit_client = ScalekitClient( env_url=os.environ["SCALEKIT_ENV_URL"], client_id=os.environ["SCALEKIT_CLIENT_ID"], client_secret=os.environ["SCALEKIT_CLIENT_SECRET"], ) actions = scalekit_client.actions response = actions.get_or_create_connected_account( connection_name="outreach", # must match the dashboard connection name identifier="user_123", ) if response.connected_account.status != "ACTIVE": link = actions.get_authorization_link( connection_name="outreach", identifier="user_123", ) print("Authorize Outreach:", link.link)

Retrieve the authorized tool surface, then run the agent

Before the code, the distinction that matters. actions.langchain.get_tools does not load a connector catalog. It returns the tools this specific rep's connected account is authorized to call, in native LangChain StructuredTool form. Scope is a function of identity, not connector configuration.

from langchain_openai import ChatOpenAI from langchain_core.messages import HumanMessage, ToolMessage tools = actions.langchain.get_tools( identifier="user_123", connection_names=["outreach"], page_size=100, # the connector exceeds the default page ) tool_map = {t.name: t for t in tools} llm = ChatOpenAI(model="gpt-4o").bind_tools(tools) messages = [ HumanMessage( "Which sequences am I running with reply rates worth reviewing, " "and which prospects have gone quiet for 14 days?" ) ] 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"]))

The same pattern in TypeScript

For Node teams, listScopedTools accepts a toolNames filter, which is where surface reduction happens explicitly. Handing the model all 53 Outreach tools at roughly 200 tokens each burns over 10,000 tokens before the agent does any work, and measurably degrades selection accuracy. This is a core consideration covered in LangChain tool calling patterns as well.

npm install @scalekit-sdk/node @anthropic-ai/sdk
import { ScalekitClient } from '@scalekit-sdk/node'; 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 { tools } = await scalekit.tools.listScopedTools('user_123', { filter: { connectionNames: ['outreach'], toolNames: [ 'outreach_sequences_list', 'outreach_sequence_states_list', 'outreach_prospects_list', 'outreach_tasks_list', ], }, 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: 'Summarize my active sequences and overdue tasks.' }, ]; while (true) { const response = await anthropic.messages.create({ model: 'claude-sonnet-4-6', max_tokens: 1024, 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: 'user_123', toolInput: block.input as Record<string, unknown>, }); 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 }); }

One connector quirk worth knowing

outreach_tasks_complete only works for action_item and in_person tasks; call and email tasks cannot be completed this way. Use it rather than outreach_tasks_update when the intent is completion. Full parameter schemas live on the Outreach connector docs.

Virtual MCP servers for multi-tenant Outreach agents

If you want the MCP interface without inheriting the Amplify gate, the DCR client requirement, and the seat-per-agent-identity constraint, Virtual MCP servers give you a scoped MCP endpoint over the connector you already configured.

Create the server once per agent role

You declare which connections and which tools the endpoint exposes. Do this once per agent role, not once per user. The response carries a static mcp_server_url.

from scalekit.actions.models.mcp_config import McpConfigConnectionToolMapping vmcp_response = scalekit_client.actions.mcp.create_config( name="outreach-pipeline-agent", connection_tool_mappings=[ McpConfigConnectionToolMapping( connection_name="outreach", tools=[ "outreach_sequences_list", "outreach_sequence_states_list", "outreach_prospects_list", "outreach_tasks_list", ], ), ], ) config_id = vmcp_response.config.id mcp_server_url = vmcp_response.config.mcp_server_url

Confirm the connection, then mint a session token per run

Check that the rep's connected account is still active before every run, because OAuth grants expire and get revoked. Then mint a short-lived token bound to that user.

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

Why this matters for a multi-tenant revenue agent

One server definition serves every rep across every customer org. Each run receives a token scoped to that individual's connected accounts, so rep A's sequences are never reachable by an agent acting for rep B on the same connection.

The endpoint is static; the identity is not. There is no MCP server to deploy, host, or maintain, and no per-user server configuration. Setup details are in set up and connect a Virtual MCP server.

Observability for downstream Outreach tool calls

Attribution is the thing that quietly breaks first, and it is the thing your customer's security reviewer asks about first.

What a shared token costs you

A shared service account looks correct in a demo. In production every prospect created, every sequence enrollment, and every deleted record shows one actor in Outreach's activity history. When a rep asks why a prospect got enrolled in the wrong cadence, the trail ends at a bot.

What per-user resolution gives you

Because Scalekit resolves the individual rep's credential before each call, Outreach's own activity history attributes the action to that rep. Scalekit's audit trail for agent auth carries the correlating record: which user, which tool, what came back, with 90 days of history that streams to your SIEM.

That is what turns "the agent enrolled 400 prospects" from an investigation into a query. For teams thinking about agent tool observability more broadly, per-user attribution is the foundation everything else is built on.

Which one to build against

If your Outreach agent is interactive, user-present, and its job is retrieval and briefing, the hosted MCP server is the faster route, and the AI-native tools are genuinely differentiated. Confirm Amplify coverage across your customer base before you build on it.

If your agent updates records, runs on a schedule, needs tasks or templates or call logging, subscribes to webhooks, or moves volume, use the REST API. The absence of update tools on MCP is a stated product position, not a gap waiting to close.

Most production revenue agents will end up running both, and the credential layer underneath is identical either way. That is the part that needs production-grade infrastructure.

Talk to other Outreach agent builders

Building on Outreach and hitting the 14-day refresh window, the Amplify gate, or per-rep attribution? Bring it to the Scalekit Slack community, or talk to an engineer if you want help mapping your agent to the right path.

Browse the Scalekit Outreach connector or read the Outreach connector documentation.

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.