Announcing CIMD support for MCP Client registration
Learn more

ZoomInfo MCP vs ZoomInfo API for AI Agents (2026)

Nishant Choudhary
Tech Evangelist

TL;DR

  • ZoomInfo's hosted MCP server exposes 22 tools: 18 direct data tools plus 4 context agents that synthesize CRM and conversation history. The REST platform adds everything operational: GTM Studio audience creation and enrichment jobs, marketing audience uploads, Agent Team runs, GTM configuration writes, and webhooks.
  • ZoomInfo MCP is one of the few vendor MCP servers that supports both Authorization Code with PKCE and Client Credentials. Headless agents are not locked out by auth. They are limited by a read-oriented tool surface and by model-chosen tool selection.
  • The service-account flow costs you more than attribution. ZoomInfo assembles per-user context server-side, so requests containing the word "my" resolve against the signed-in rep's calendar, book of business, and CRM ownership. With one shared identity there is nothing to resolve against.
  • Tool bloat on ZoomInfo is a billing problem, not just a token problem. Search, lookup, and find-similar are free; enrich and the context agents draw bulk data and AI action credits. An over-scoped surface lets the model reach for a paid tool when a free one would answer.
  • Both paths hand you one credential per user and neither stores, refreshes, or revokes it. Scalekit's ZoomInfo connector vaults the per-user token, resolves it at request time, and logs every tool call against the rep who authorized it, so the MCP vs API decision does not change your auth infrastructure.

Your agent needs ZoomInfo. It has to size a territory, surface accounts showing intent, map the buying committee, and enrich the three contacts worth emailing. ZoomInfo now ships a hosted MCP server at mcp.zoominfo.com/mcp alongside a rebuilt REST platform at docs.zoominfo.com, and both hit the same backend, the same entitlements, and the same credit pool. The difference is not data coverage. It is who picks the tool, whether the surface can write, and what your agent owes the credential layer afterward. Here is how to pick.

What ZoomInfo MCP and the ZoomInfo API actually are

These are two front doors onto one backend. ZoomInfo says so directly: the MCP server, the CLI, and the REST API respect the same entitlements and draw on the same credits. What separates them is the calling convention and the write surface.

ZoomInfo MCP

ZoomInfo runs a hosted, remote MCP server over Streamable HTTP at a single endpoint, https://mcp.zoominfo.com/mcp. Every client connects to the same URL. Authentication runs through ZoomInfo's MCP Gateway, which enforces entitlements per call and keeps the server stateless: each tool call is scoped to the authenticated user rather than to a session.

The tool catalog splits in two. Direct tools return structured records: lookup, company and contact search, enrichment, lookalikes, intent, scoops, news, audiences, and engagements. Context agents run a sub-agent layer that blends ZoomInfo's third-party data with your organization's first-party CRM and conversation history, then returns a synthesized briefing. Details live on the ZoomInfo MCP product page and the ZoomInfo MCP tool reference.

The ZoomInfo API platform

The REST platform at docs.zoominfo.com exposes search, enrich, lookup, usage, signals, GTM Studio audiences, marketing audiences, Agent Teams, GTM configuration objects, and webhooks and events. Applications come in two shapes registered in the ZoomInfo Developer Portal. Standard apps are for your own internal or single-tenant use and support both OAuth flows. Partner apps are built by approved partners for distribution across customer organizations and must use Authorization Code with PKCE.

The legacy credential surface you may still be carrying

Older Enterprise API integrations do not use OAuth at all. They exchange either a username and password, or a client ID and RSA private key, for a JWT that is valid for one hour, using ZoomInfo's published Python PKI auth client. There is no refresh token in that model, so long-running pipelines have to re-authenticate proactively. If your agent inherits one of these credentials, treat it as a migration item, not a design choice.

Comparing them where it matters for agents

Four dimensions decide this for a production agent: what each surface can do, what auth it accepts, what identity it acts under, and what you own operationally once it ships.

What your agent can actually do

The MCP surface is built for research. The API surface is built for research plus everything that happens after the research: writing lists, running jobs, and reacting to change.

Capability
ZoomInfo MCP
ZoomInfo API
Company and contact search
Yes
Yes
Company and contact enrichment
Yes, up to 25 records per call
Yes
Intent, scoops, and news signals
Yes
Yes
Lookalikes and contact recommendations
Yes
Yes
Org charts, technographics, corporate hierarchy
Not exposed as MCP tools
Yes
Synthesized account and contact research
Yes, via context agents
No equivalent single call
Conversation intelligence across calls and emails
Yes, via context agent
Not exposed
Browse GTM Studio audiences
Yes, read only
Yes
Create audiences, upsert rows, run enrichment jobs
No
Yes
Marketing audience upload and removal
No
Yes
Write GTM config: ICPs, personas, competitors, offerings
Only GTM context
Yes
Trigger and poll Agent Team runs
No
Yes
Webhooks and event subscriptions
No
Yes

The read-only ceiling, and the one write that is not

ZoomInfo's own security documentation states that all MCP tools are currently read-only and that no data is written back through the MCP connection. The tool catalog is one step ahead of that statement: update_gtm_context writes GTM configuration, and ZoomInfo's first-session prompt tells users to call it. Treat the surface as read-oriented with a single configuration write.

That distinction matters for scoping. Every other mutation your agent might want — creating an audience from a search result, upserting 500 rows, kicking off an enrichment job, uploading a marketing audience — lives only on the API. If the agent's output is a list somebody else consumes, the API is not optional.

The auth path each one puts you on

This is where ZoomInfo diverges from most vendor MCP servers. Its MCP server supports two OAuth flows, not one. User sign-in uses Authorization Code with PKCE, where each person authenticates with their own ZoomInfo login. Service accounts use Client Credentials, where the app authenticates once as itself and no individual signs in.

The REST platform accepts the same two flows through the Developer Portal. So the usual headless blocker does not apply here: a background agent can hold a ZoomInfo MCP credential without a browser in the loop. For a deeper look at tool calling auth production problems and patterns, the tradeoffs between these flows apply across most vendor connectors.

The entitlement gates that decide who can connect

Auth method is settled. Provisioning is not, and it is where first connections fail.

Connecting an AI client to the hosted MCP works on any ZoomInfo subscription. Registering your own app for API or MCP use requires a DevPortal subscription assigned by a ZoomInfo admin. Per-user MCP connectivity is then governed by an API Access toggle under Admin Portal, Users, User Management, and there is no organization-wide kill switch; access is managed one user at a time. Admin-only seats have no data access by design and cannot connect through any path.

Where the service account quietly costs you accuracy

Auth choice is not only a security posture on this connector. It changes what answers exist.

ZoomInfo assembles per-user context on the server side from the signed-in user's models. "Research the accounts I'm meeting with this week" resolves against that rep's calendar. "Show me my renewals and what those accounts said on recent calls" resolves against their book of business and their call recordings. Under Client Credentials there is no signed-in user, so those requests either fail or degrade to a generic company-level answer. ZoomInfo recommends user sign-in wherever it is practical for exactly this reason.

The pattern here is the one Scalekit keeps running into across connectors: what the user can't do, the agent can't do, and what the user alone can see, a shared identity can't reach. This is the core challenge of moving tool calling auth from single-tenant to multi-tenant environments.

Rate limits run on three windows at once

Every API request is evaluated against per-second, per-hour, and per-day windows simultaneously, and any exhausted window returns 429. Rejected requests do not consume quota, and X-RateLimit-Rejected-Bucket tells you which window to back off from.

Package
Per second
Per hour
Per day
Builder
5
10,800
129,600
Standard
25
54,000
648,000
Scaling
35
75,600
907,200

An exhausted hourly bucket can return a Retry-After in the hundreds of seconds, so a fixed one-second retry loop will not recover.

Credits are a second budget your model is spending

This is the part agent builders underestimate. Search, lookup, and find-similar consume no credits. Enrichment draws bulk data credits, and the context agents draw AI action credits.

MCP specifically requires bulk data credits rather than recurring monthly credits, which is the most common cause of a failed first connection. Records Under Management keeps the math honest across surfaces: once a record is enriched anywhere in the platform, it stays under management for 12 months at the organization level and is not charged again in that window. Enrich an account through the API on Monday and read it in Claude on Friday, and you paid once.

What you own in production

On the MCP path, ZoomInfo owns hosting, gateway auth, entitlement enforcement, and tool schema updates. New tools appear automatically at the start of each session, with no redeploy on your side. You own per-user token storage, refresh, revocation, and the credit budget the model spends on your behalf.

On the API path you own all of that plus request construction, pagination, Retry-After handling per rejected bucket, and adapter code per surface. What you get back is determinism. ZoomInfo's own comparison is blunt about it: with MCP, output varies with how the model reasons; with REST, the schema is fixed. Understanding who holds the token across agent tool-calling patterns is essential before committing to either path.

What the nondeterminism costs, measured

For a nightly enrichment pipeline where an unexpected tool substitution is an incident, that difference decides the architecture on its own. There is a token cost attached to it as well.

ZoomInfo's GTM Bench v1 benchmark, run across ten B2B research tasks, put the MCP arm at 1.48M work tokens and $15.80, against 460K tokens and $10.12 for its own CLI arm on identical work. MCP finished fastest at 32 minutes and posted the highest verified-email coverage at 94 percent. It is vendor-published and measures coverage rather than correctness, so read it as a signal on efficiency and fill rate, not precision. For context, MCP can be up to 32× more expensive than CLI — a tradeoff worth understanding before you commit to the transport.

When to use MCP, when to use the API

Use ZoomInfo MCP when:

  • The agent is interactive and the answer depends on who is asking: pre-call briefings, buying-committee mapping, "what happened on my accounts this week"
  • You want the context agents, since Account Research and Conversation Intelligence have no single-call REST equivalent
  • You are validating a GTM agent concept and want ZoomInfo's tool descriptions rather than writing schemas against search and enrich endpoints
  • You are orchestrating ZoomInfo alongside other MCP tools and want one discovery convention across all of them

Use the ZoomInfo API when:

  • The agent writes: creating GTM Studio audiences, upserting rows, running enrichment jobs, uploading marketing audiences, or maintaining ICPs, personas, and competitor records
  • The agent needs org charts, technographics, or corporate hierarchy, which are on the REST surface but not exposed as MCP tools
  • The agent must react to change through webhooks rather than polling
  • You are running a deterministic pipeline at volume and need fixed schemas, explicit pagination, and rate-limit headers you can throttle against
  • The agent triggers and polls Agent Team runs as part of a larger workflow

Building a ZoomInfo agent with Scalekit

The decision above changes what your agent can do. It does not change what you have to build underneath it. Scalekit's ZoomInfo connector sits on the OAuth path and gives both shapes the same credential layer.

One connector, two delivery shapes

Some vendors get two Scalekit connectors, one for the REST API and one wrapping the vendor's hosted MCP server. ZoomInfo currently gets one: the Scalekit ZoomInfo connector, authenticated with OAuth 2.0 against a ZoomInfo Developer Portal app, covering the full REST surface including the audience, Agent Team, and GTM configuration writes that the hosted MCP does not expose.

If you want that surface delivered as MCP rather than as native tool objects, you do not switch connectors. You compose a Virtual MCP server over it and get a per-user MCP endpoint carrying exactly the tools you allow. The capability set stays a superset of the hosted server's; the transport becomes your choice rather than the vendor's.

Set up the connection once per environment

Create an app at developer.zoominfo.com, set the redirect URI to your Scalekit redirect URI, and copy the client ID and secret. In the Scalekit dashboard, go to AgentKit, then Connections, then Create Connection, search for ZoomInfo, and paste both values.

Note the connection name shown on that screen. It is the string you pass as connection_name in code, and a mismatch here is the single most common integration error.

Authorize a rep

Install the SDK and resolve the connected account. If the rep has not authorized yet, hand them a magic link.

pip install scalekit-sdk-python langchain langchain-openai
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_42@acme.com" CONNECTION_NAME = "zoominfo" # 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 ZoomInfo:", magic_link.link) input("Press Enter after authorizing...")

Retrieve the authorized tool surface, then run the agent

Before any tool object reaches the model, understand what this call is doing. The agent is not loading the ZoomInfo connector catalog. It is loading the tools this rep's connected account is authorized to call, filtered further to the ones this agent role needs. That distinction is what separates a per-user agent from a shared-credential agent.

The filter matters more on ZoomInfo than on most connectors, because the tool surface is also a spend surface. zoominfo_search_companies and zoominfo_lookup_data are free. zoominfo_enrich_contacts bills per matched record. Handing the model both without constraint invites it to enrich when it should have searched.

from langchain_openai import ChatOpenAI from langchain_core.messages import HumanMessage, ToolMessage tools = actions.langchain.get_tools( identifier=IDENTIFIER, connection_names=[CONNECTION_NAME], tool_names=[ "zoominfo_lookup_data", "zoominfo_search_companies", "zoominfo_search_intent", "zoominfo_get_contact_recommendations", "zoominfo_enrich_contacts", ], page_size=100, ) tool_map = {t.name: t for t in tools} llm = ChatOpenAI(model="gpt-4o").bind_tools(tools) messages = [ HumanMessage( "Find US software companies with 200 to 2000 employees showing intent on " "customer identity management. Take the top account, recommend contacts for " "a prospecting motion, and enrich the best three with verified email." ) ] while True: response = llm.invoke(messages) messages.append(response) if not response.tool_calls: print(response.content) break for tool_call in response.tool_calls: result = tool_map[tool_call["name"]].invoke(tool_call["args"]) messages.append( ToolMessage(content=str(result), tool_call_id=tool_call["id"]) )

The same surface in TypeScript with the Claude SDK

If your stack is Node, listScopedTools returns schemas in Anthropic's native shape, so there is no conversion step between discovery and the tool-use loop.

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 identifier = 'rep_42@acme.com'; const { tools } = await scalekit.tools.listScopedTools(identifier, { filter: { connectionNames: ['zoominfo'], toolNames: [ 'zoominfo_search_companies', 'zoominfo_get_contact_recommendations', 'zoominfo_enrich_contacts', ], }, 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: 'Map the buying committee at ZoomInfo company ID 344589814 for a prospecting motion, then enrich the top three contacts with email and direct phone.', }, ]; 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, 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 }); }

Expose ZoomInfo as a per-user MCP endpoint

For multi-tool and multi-tenant agents, the native tool objects above stop being the right delivery shape. You want one endpoint per agent role, carrying ZoomInfo alongside your CRM and your Slack connector, resolving to a different identity on every run.

Define the config once, then call ensure_instance per user. It is idempotent, so call it on every session.

from scalekit.actions.types import McpConfigConnectionToolMapping actions.mcp.create_config( name="gtm-research-agent", description="Read-only ZoomInfo research surface for the pre-call briefing agent", connection_tool_mappings=[ McpConfigConnectionToolMapping( connection_name="zoominfo", tools=[ "zoominfo_search_companies", "zoominfo_search_intent", "zoominfo_get_account_summary", "zoominfo_get_contact_recommendations", ], ) ], ) instance = actions.mcp.ensure_instance( config_name="gtm-research-agent", user_identifier=IDENTIFIER, ) mcp_url = instance.instance.url

Before the run, confirm the rep has authorized everything the config needs, and surface a fresh link for anything that has lapsed.

auth_state = actions.mcp.get_instance_auth_state( instance_id=instance.instance.id, include_auth_links=True, ) for connection in auth_state.connections: if connection.connected_account_status != "ACTIVE": print(f"{connection.connection_name} needs authorization: {connection.authentication_link}")

The two properties this buys you are the ones the hosted ZoomInfo server cannot give you. The agent sees only the tools you explicitly allow, not everything the connector exposes, so a research agent has no path to zoominfo_delete_audience no matter what the prompt says. And one server definition serves every tenant, with identity supplied at runtime rather than baked into a per-customer deployment.

Downstream tool-call auth logs

The gap that shows up in enterprise procurement is not "did the call succeed." It is "which rep authorized this enrichment, under which grant, and was that grant still valid when it ran."

Every execute_tool call through Scalekit lands in one audit log keyed to the authorizing user, alongside the connection ID, scope grants, token lifecycle events, and revocation state for that OAuth grant. For a connector that bills per record and touches contact data subject to GDPR, that record is the difference between a three-week investigation and a query. This is exactly why audit trails for agent auth in B2B SaaS have moved from nice-to-have to procurement requirement. Standard application logs capture the API call at the end of the chain and nothing before it.

The credential problem that exists on both paths

Pick MCP or pick REST. Either way, every rep using your agent has their own ZoomInfo credential.

N reps, N credential lifecycles

Forty reps across eight customer orgs is forty OAuth grants to store encrypted, refresh before expiry, and revoke on offboarding. Neither ZoomInfo path gives you a vault, rotation logic, or a revocation flow; ZoomInfo enforces identity and entitlements, it does not manage the credential lifecycle for you. The failure mode is familiar: the Okta account gets disabled, and a ZoomInfo grant issued eight months ago keeps working. The agent does not decide to keep using it. It just does. Understanding how to handle token refresh for AI agents is the first operational problem every production agent team faces.

Where Scalekit fits

Scalekit's ZoomInfo connector handles the OAuth flow, per-tenant encrypted token storage, and automatic refresh for both paths, so the MCP vs API decision does not change your auth infrastructure. The credential is resolved server-side at request time and never enters your agent runtime, your logs, or the LLM context.

Which one to build against

If a rep is present and the question contains the word "my," build on ZoomInfo MCP. The per-user context resolution and the context agents are the reason that surface exists, and neither has a clean REST equivalent.

The line that decides it

If the agent writes a list, runs a job, subscribes to an event, or executes on a schedule at volume, build on the API. The read-oriented tool surface is not a temporary gap; it reflects what ZoomInfo designed the MCP server to do.

Most production GTM agents end up running both, and the credit pool does not care which one spends it. What both paths leave on your side of the line is the same: N credentials, N lifecycles, and an audit trail somebody in procurement will eventually ask to see.

Get help from other ZoomInfo agent builders

Browse the Scalekit ZoomInfo connector or read the connector docs for the full tool list.

Building something on ZoomInfo and want a second opinion on the auth model? Join the Scalekit Slack community or talk to us for immediate help.

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.