Announcing CIMD support for MCP Client registration
Learn more

Clay MCP vs Clay API for AI Agents (2026)

Nityashree Yadunath
Product Marketing Manager

TL;DR

  • Clay MCP and the Clay Public API have overlapping but not identical coverage. MCP owns Audiences querying, natural-language account Q&A, and per-rep credit governance. The Public API owns database-wide structured search, batch runs over JSONL, Enterprise table queries, and signed webhooks.
  • MCP auth is OAuth only. There is no static credential path on either the hosted server or the local clay mcp CLI server, both of which resolve a browser-established session. The Public API authenticates with a clay-api-key header tied to a specific Clay user and their workspace access.
  • Clay's credit budgets, function-level permissions, and usage monitoring are scoped to MCP users. If your background agent runs on a Public API key, none of those guardrails apply to it.
  • Clay admins cannot directly revoke a rep's MCP connection from the MCP users page. The documented options are removing the user from the workspace or dropping their credit limit to zero. That is a revocation gap you have to model in your own infrastructure.
  • Scalekit's Clay MCP connector handles the OAuth flow, per-user token storage, and refresh, and a custom connector covers the Public API path through Tool Proxy, so the MCP vs API decision does not change your auth infrastructure.

Your agent needs to find accounts, enrich contacts, and run your team's GTM logic in Clay. Clay ships a hosted Model Context Protocol (MCP) server that Claude, ChatGPT, and Codex connect to as a one-click connector, and a Public API at api.clay.com/public/v0 that your backend calls with a key. They are not two views of the same surface. They expose different primitives, they authenticate differently, and one of them cannot run without a browser. Here's how to pick.

What Clay MCP and Clay API actually are

Clay exposes three developer surfaces, not two, and conflating them is the first source of confusion. There is a hosted MCP server aimed at reps inside AI assistants, a local MCP server that ships with the Clay coding-agent plugin, and a Public API for backend systems. Each has its own auth model.

Clay MCP, the hosted connector

The hosted server is what Clay markets as Clay MCP. It exposes 150+ data providers, AI research agents, and your team's prebuilt Functions inside ChatGPT, Claude, and Codex. Clay's own docs also list Microsoft Copilot and Glean as supported hosts.

Auth is OAuth with Dynamic Client Registration. Clay distributes the connection as one-click connector cards inside each assistant rather than publishing the raw URL in-product; the endpoint the official connector points at is https://api.clay.com/v3/mcp. Workspace admins govern access, Function availability, and credit budgets from the MCP settings page.

Clay MCP, the local CLI server

Clay also ships an agent plugin that installs the clay CLI plus a local stdio MCP server started with clay mcp. This one is built for coding-agent hosts: Claude Code, Codex, and Cursor. Clay's MCP server documentation is explicit that general-purpose chat apps cannot use it, because the plugin also needs a shell to run the CLI.

It authenticates from the session established by clay login, resolved once at process startup. That has a specific operational consequence: the connection stays pinned to whichever workspace was active at launch, and switching workspaces requires the host to restart the server. Note that a local stdio process is not a deployment target for a hosted multi-tenant agent.

The Clay Public API

The Clay Public API is the programmatic surface for backend jobs, internal tools, queues, and product features. Base URL is https://api.clay.com/public/v0. It covers four primitives: routines (Clay-managed functions, custom functions, and Workflows in Alpha), searches over Clay's proprietary GTM database, tables, and runs.

Authentication is a single header. Every request carries clay-api-key, and keys are created under Settings, Account, API keys, currently labeled beta. Keys are tied to a Clay user and that user's workspace access, which matters more than it looks; more on that below.

The timeline that matters for maturity judgments

Clay's MCP surface is young and moving. Clay in ChatGPT shipped December 17, 2025. The Clay connector in Claude followed on January 26, 2026. Functions, MCP permissioning, and credit budgets landed April 22, 2026, and Codex support on June 2, 2026.

Treat this as a surface that will gain tools quarterly. Treat the Public API as the slower-moving contract, with the caveat that API keys are in beta and Workflows are in Alpha.

Comparing them where it matters for agents

The two paths diverge along four axes: what the agent can call, what identity it acts as, what you operate, and what breaks first. Start with capability, because for Clay the gap is unusually asymmetric. Each surface has exclusive territory the other cannot reach.

What your agent can actually do

Scalekit's Clay MCP connector surfaces 16 tools from the hosted server, which is a reasonable proxy for the current tool inventory. The Public API surfaces roughly a dozen endpoints across four primitives. Neither is a superset.

Capability
Clay MCP (hosted)
Clay Public API
Find and enrich a company by domain or LinkedIn URL
Yes (claymcp_find_and_enrich_company)
Partial: run a Clay-managed or custom function routine
Find contacts at a company by title, role, or department
Yes (claymcp_find_and_enrich_contacts_at_company)
Partial: same routine pattern
Database-wide structured-filter search across people and companies
No: searches are anchored to a company or a named list
Yes (POST /search/filters-mode plus a paged iterator)
Run a custom Function
Yes (claymcp_run_subroutine, claymcp_run_subroutine_direct)
Yes (POST /routines/{routine_id}/run)
Batch execution over large input sets
No
Yes: presigned JSONL upload, then run-batch
Natural-language query over Clay Audiences
Yes (claymcp_query_objects), Enterprise beta
No
AI question answering across account data, calls, and emails
Yes (claymcp_ask_question_about_accounts)
No
Read Clay table records with filters, field selection, and cursors
No
Yes (POST /tables/query), Enterprise plans
Event notification when a run finishes
No
Yes: signed delivery with X-Clay-Signature
Poll async task state and read enrichment values
Yes (claymcp_get_task, claymcp_get_task_context)
Yes: routine run results endpoints
Check remaining workspace and rep credits
Yes (claymcp_get_credits_available)
Not documented
Per-rep credit budget enforcement
Yes: MCP users settings
Not documented

Where the MCP surface genuinely wins

Three MCP tools have no API equivalent, and they are not minor. claymcp_query_objects translates plain language into structured filters over Clay Audiences, with an onlyMine flag that restricts results to the caller's Salesforce-owned accounts. claymcp_ask_question_about_accounts runs an AI agent across account data including contacts, opportunities, Gong calls, and emails.

claymcp_get_credits_available returns workspace, sales-rep, and budget credit availability, which lets an agent check spend headroom before it burns a run. There is no documented Public API endpoint for any of these. If your agent's job is account intelligence over data Clay has already unified, MCP is the only path.

Where the API surface genuinely wins

The Public API owns everything shaped like a pipeline. POST /search/filters-mode creates a structured-filter search over Clay's proprietary database of people and companies, with a fields catalog you call first to build valid filters, and a stateful iterator you page through until has_more is false.

Batch runs handle volume the MCP surface has no concept of: issue a presigned URL, upload JSONL, start a run-batch, and read results asynchronously. Inline routine runs accept 1 to 100 items. Webhooks close the loop: register an endpoint with clay webhooks create, pass its webhook_id when you start a run, and Clay sends a signed POST when results are ready. Clay documents delivery as not guaranteed and recommends keeping polling as a fallback.

The naming mismatch that will bite you

Clay calls the same concept three things depending on which surface you are reading. In the product it is a Function, a reusable enrichment workflow an admin builds once. In the Public API it is a routine, with custom function routine ids formatted as function:t_....

In the MCP tool surface it is a subroutine: claymcp_list_subroutines is documented as listing available custom functions in the workspace. Budget an hour for the mapping when you first wire this up, and note that every Clay MCP tool requires a rationale string argument explaining why the agent is calling it.

The auth path each one puts you on

Capability differences are solvable with a second integration. Auth differences are not, because they determine whether your agent can run at all when no human is present. This is where the Clay decision actually gets made.

MCP is OAuth, and only OAuth

The hosted server authenticates with OAuth 2.1 and Dynamic Client Registration. The local server authenticates from the session clay login writes to disk after a browser round trip. Neither accepts an API key.

That is a hard constraint for headless execution. A nightly enrichment sync, a scheduled account-scoring job, or an inbound-lead pipeline running without a user in the loop cannot complete a browser consent flow on its own. You either pre-establish a session per user and manage its lifecycle, or you use the API. For a deeper look at why OAuth is essential for AI agents acting on behalf of users, the tradeoffs are well-documented.

The API is a static key, scoped to one person

The Public API accepts one credential type, passed as clay-api-key. It is not a service account. Clay documents API keys as tied to a Clay user and that user's workspace access.

The practical reading: a Public API key inherits a human's permissions and lives or dies with that human's presence in the workspace. If the GTM engineer who minted the key leaves, your background pipeline is running on a credential attached to a departed employee. That is the same offboarding failure mode that shows up with personal access tokens everywhere else, and Clay does not offer an org-scoped alternative today.

What this means for multi-tenant agents

For a B2B product where every customer has their own Clay workspace, both paths produce one credential per user or per workspace. MCP gives you an OAuth grant per rep. The API gives you a key per workspace, minted by one person in it.

Neither path ships storage, rotation, revocation, or tenant isolation. Those remain yours regardless of the choice, and the Clay-specific revocation gap covered below makes them harder than average. Understanding who holds the token across agent tool-calling patterns is essential before you finalize your architecture.

What you own in production

Clay manages the hosted MCP server, its tool schemas, and the enrichment providers behind them. On the API path Clay manages the endpoints and the async run infrastructure. Everything between your agent and those surfaces is yours. Three areas need explicit design.

Credit budgets exist on one path only

Clay's governance layer is real and worth using. Admins set a default credit limit for every new MCP user, override it per rep, and watch live consumption in the MCP users table. Spend resets on the first of each month at midnight UTC. When a rep hits their limit, further actions are hard-blocked until reset.

Function-level permissions sit alongside it: admins toggle Enable for MCP per Function, so reps only see vetted workflows.

All of this is documented against MCP users. No equivalent per-key budget control is documented for the Public API, so a runaway background loop on that path has no Clay-side circuit breaker. Build your own spend ceiling first.

Rate limits and async result handling

Clay enforces a per-workspace rate limit on the Public API and returns 429 with a Retry-After header, plus X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset when available. Clay does not publish a numeric ceiling, so instrument for it rather than assuming one.

The recommended handling is exponential backoff with jitter, and a preference for batch and async endpoints over tight polling loops. On the MCP path the same asynchrony exists but is expressed as tasks: enrichment tools return a taskId, and the agent reads results with claymcp_get_task_context. Design your agent loop to tolerate a pending task rather than blocking on it.

Schema drift and versioning

The hosted MCP tool schemas change when Clay updates the server. There is no version header to pin, and the tool inventory has grown repeatedly since December 2025. An agent built against a specific tool signature can find that signature restructured without a deploy on your side.

The Public API is more stable in practice but carries its own caveat: API keys are in beta and Workflows are in Alpha. For deterministic pipelines where an unplanned schema change is an incident, the API is the more predictable dependency, but neither surface is frozen. Pin what you can and monitor tool-listing diffs on the MCP path.

When to use MCP, when to use the API

The split is cleaner for Clay than for most tools, because the exclusive capabilities on each side are load-bearing rather than convenience features. Use the presence of a human, and the presence of Audiences data, as your two deciding variables.

Use Clay MCP when

  • Your agent is interactive and user-facing: a rep-facing assistant where the person is present for the OAuth consent and the request is 1 to 20 contacts, not 5,000
  • The agent needs Clay Audiences: claymcp_query_objects and claymcp_ask_question_about_accounts have no Public API equivalent
  • You want Clay's admin governance without building your own: function-level permissions and per-rep credit budgets come with the path
  • Your agent runs inside a coding-agent host and needs Clay alongside the clay CLI, in which case the local plugin server is the right variant
  • You want the enrichment defaults reps already trust, including headcount growth, tech stack, funding, and work history, without composing them yourself

Use the Clay Public API when

  • Your agent runs headless: scheduled enrichment syncs, inbound-lead scoring, CRM hygiene jobs, or anything without a browser at execution time
  • You need database-wide prospecting: structured-filter searches over Clay's people and company data with a paged iterator
  • Volume is the point: presigned JSONL upload plus run-batch is the only path above 100 items per run
  • Your agent must react to completion events rather than poll, using signed webhooks with X-Clay-Signature verification
  • You are building on Clay tables as a GTM database for dashboards, QA views, or scoring jobs, which is Enterprise-only and API-only
  • You control endpoint versioning and cannot absorb unannounced tool schema changes

The credential problem that exists on both paths

Whichever path you pick, every user in your agent system ends up with their own Clay credential. Fifty reps means fifty OAuth grants on the MCP path, or a set of workspace keys each minted by a specific person on the API path. Clay does not store, rotate, or revoke any of them for you.

Revocation is the sharp edge in Clay specifically

Most tools give you a clean per-connection kill switch. Clay's MCP settings documentation is explicit that admins cannot directly revoke a rep's MCP connection from the MCP users page. The two documented options are removing the rep from the workspace entirely, or setting their credit limit to a low value to throttle usage.

That is a workaround, not a revocation primitive. On the API path it is worse: a clay-api-key is a static string tied to a user, and nothing in your agent tells you when it stops being appropriate for that user to hold it. Your agent finds out on the next 401, if you are watching for it. This is exactly the scenario explored in what happens when an employee leaves and who revokes their AI agent's access.

The N-credential problem

In a multi-tenant B2B agent, which is the default rather than the exception, each credential needs to be encrypted at rest, isolated per tenant, refreshed before expiry rather than after a 401, and invalidated the moment an employee is offboarded. The token type differs between the two paths. The infrastructure required does not.

Scalekit's Clay connector handles the OAuth flow, per-user token storage, and refresh for the MCP path, and a custom connector covers the Public API path through the same connected-account model, so the MCP vs API decision does not change your auth infrastructure. For a detailed look at secure token management for AI agents at scale, the patterns apply directly here.

Building Clay agents with Scalekit

Scalekit ships Clay as an MCP connector under the slug claymcp, authenticating over OAuth 2.1 with Dynamic Client Registration. Full tool schemas live on the Clay MCP connector docs page, and the Clay MCP connector page covers the auth lifecycle. Configure the connection in the dashboard first; the connection_name string in your code must match it exactly, and that mismatch is the single most common integration error.

Connect the Clay MCP connector

Install the SDK and set your Scalekit credentials, then create a connected account for the user and send them through Clay's OAuth flow. The connected account is the record that holds their Clay grant.

pip install scalekit-sdk-python python-dotenv anthropic
import os import scalekit.client from dotenv import load_dotenv load_dotenv() 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 # Must match the Connection name in Scalekit Dashboard > AgentKit > Connections CLAY_CONNECTION = os.getenv("CLAY_CONNECTION_NAME", "claymcp") IDENTIFIER = "user_123" # your app's stable ID for this user account = actions.get_or_create_connected_account( connection_name=CLAY_CONNECTION, identifier=IDENTIFIER, ).connected_account if account.status != "ACTIVE": link = actions.get_authorization_link( connection_name=CLAY_CONNECTION, identifier=IDENTIFIER, ) print("Authorize Clay:", link.link) # In production, redirect the user here and resume after the OAuth callback input("Press Enter after authorizing Clay...") account = actions.get_or_create_connected_account( connection_name=CLAY_CONNECTION, identifier=IDENTIFIER, ).connected_account if account.status != "ACTIVE": raise RuntimeError("Clay is still not ACTIVE. Complete authorization and retry.")

Retrieve the authorized tool surface, then run the loop

Before the agent reasons about anything, it needs to know which Clay tools this specific user's connected account is authorized to call. That is not a catalog lookup. list_scoped_tools returns the deterministic surface for one connected account, which for a Clay agent typically means 3 to 6 tools instead of the full 16, and that reduction is the difference between reliable tool selection and the model guessing.

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

With the scoped surface in hand, run the agent loop. Every execute_tool call resolves the authorizing rep's Clay credential server-side, so the enrichment spend and the audit entry both land on the right person.

import json import anthropic client = anthropic.Anthropic() messages = [{ "role": "user", "content": ( "Find the VP of Marketing at ramp.com, enrich their verified work email, " "and summarize the company's tech stack and latest funding." ), }] while True: response = client.messages.create( model="claude-sonnet-4-6", max_tokens=2048, tools=llm_tools, messages=messages, ) if response.stop_reason != "tool_use": print("".join(b.text for b in response.content if b.type == "text")) break messages.append({"role": "assistant", "content": response.content}) tool_results = [] for block in response.content: if block.type != "tool_use": continue result = actions.execute_tool( tool_name=block.name, connection_name=CLAY_CONNECTION, identifier=IDENTIFIER, tool_input=block.input, ) tool_results.append({ "type": "tool_result", "tool_use_id": block.id, "content": json.dumps(result.data, default=str), }) messages.append({"role": "user", "content": tool_results})

Clay's enrichment tools return a taskId rather than finished data, so expect the loop to run at least twice: once to create the task, once to read claymcp_get_task_context.

The same surface in TypeScript

Node applications use the same two calls with camelCase naming. Install the SDK, then retrieve the scoped surface and execute by name.

npm install @scalekit-sdk/node
import { ScalekitClient } from '@scalekit-sdk/node'; import 'dotenv/config'; const scalekit = new ScalekitClient( process.env.SCALEKIT_ENV_URL!, process.env.SCALEKIT_CLIENT_ID!, process.env.SCALEKIT_CLIENT_SECRET!, ); const CLAY_CONNECTION = process.env.CLAY_CONNECTION_NAME!; // must match the dashboard const identifier = 'user_123'; const { tools } = await scalekit.tools.listScopedTools(identifier, { filter: { connectionNames: [CLAY_CONNECTION] }, 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 result = await scalekit.actions.executeTool({ toolName: 'claymcp_find_and_enrich_company', connector: CLAY_CONNECTION, identifier, toolInput: { companyIdentifier: 'ramp.com', rationale: 'Pre-call research for an outbound sequence', }, }); // Enrichment tools return a taskId; read values with claymcp_get_task_context console.log(result.data);

LangChain adapter variant

If your agent already runs on LangChain, skip the schema reshaping. Scalekit returns native StructuredTool objects filtered to the user's authorized Clay surface.

from langchain_anthropic import ChatAnthropic from langchain.agents import create_agent tools = actions.langchain.get_tools( identifier=IDENTIFIER, connection_names=[CLAY_CONNECTION], page_size=100, ) llm = ChatAnthropic(model="claude-sonnet-4-6") agent = create_agent( model=llm, tools=tools, system_prompt="You are a GTM research assistant. Always pass a clear rationale.", ) result = agent.invoke({ "messages": [{"role": "user", "content": "Enrich the exec team at ramp.com"}] })

For more on how LangChain tool calling works and where it stops, see LangChain Tool Calling: How It Works, Where It Stops, and How Scalekit Completes It.

Taking the Clay Public API path through Scalekit

The Public API is not in Scalekit's prebuilt catalog, which is the expected shape for a beta API surface. Add it as a custom connector and it inherits the same connections, connected accounts, and audit chain as every prebuilt connector, with no separate auth stack.

Define the connector

Clay expects the credential in a clay-api-key header rather than Authorization, which is exactly what auth_header_key_override exists for. Post this payload to the custom providers management API.

{ "display_name": "Clay Public API", "description": "Run Clay routines, searches, and table queries through the Clay Public API", "auth_patterns": [ { "type": "API_KEY", "display_name": "Clay API key", "description": "Authenticate with a Clay Public API key", "auth_header_key_override": "clay-api-key", "fields": [ { "field_name": "api_key", "label": "Clay API key", "input_type": "password", "hint": "Create it in Clay under Settings > Account > API keys (beta)", "required": true } ] } ], "proxy_url": "https://api.clay.com/public/v0", "proxy_enabled": true }

Call routines through Tool Proxy

Once the connector exists and a connection is configured, REST calls go through actions.request(). Scalekit injects the vaulted key at request time, so the credential never enters your agent runtime or the model's context.

CLAY_API_CONNECTION = os.getenv("CLAY_API_CONNECTION_NAME") # match the dashboard exactly # Start an inline routine run (1 to 100 items per call) run = actions.request( connection_name=CLAY_API_CONNECTION, identifier=IDENTIFIER, path="/routines/function:t_abc123/run", method="POST", body={ "items": [ {"id": "row-1", "inputs": {"domain": "ramp.com"}}, {"id": "row-2", "inputs": {"domain": "vanta.com"}}, ] }, ) routine_run_id = run.json()["routine_run_id"] # Read results once the run completes results = actions.request( connection_name=CLAY_API_CONNECTION, identifier=IDENTIFIER, path=f"/routines/run/{routine_run_id}/results", method="GET", ) print(results.json())

The same pattern covers /search/filters-mode for database-wide prospecting and /tables/query for Enterprise table reads. Treat 429 as retryable, honor Retry-After, and prefer the webhook callback over a tight polling loop.

Virtual MCP for multi-tool, multi-tenant GTM agents

A Clay agent is almost never a Clay-only agent. It finds a contact, writes it to Salesforce or HubSpot, and posts to Slack. Wiring three MCP servers into one agent means three tool catalogs in context and three credential lifecycles at runtime. Virtual MCP Servers collapse that into one endpoint.

One server definition, per-user tokens

A standard MCP server exposes every tool it has. Clay's exposes 16, most of which a pipeline agent will never call. Virtual MCP enforces least privilege at the tool level: declare exactly which tools from which connections the agent can see, get a static mcp_server_url once per agent role, then mint a short-lived session token per user before each run.

from datetime import timedelta from scalekit.actions.models.mcp_config import McpConfigConnectionToolMapping vmcp = scalekit_client.actions.mcp.create_config( name="gtm-account-research-agent", connection_tool_mappings=[ McpConfigConnectionToolMapping( connection_name=CLAY_CONNECTION, tools=[ "claymcp_find_and_enrich_contacts_at_company", "claymcp_get_task_context", "claymcp_get_credits_available", ], ), McpConfigConnectionToolMapping( connection_name="salesforce", tools=["salesforce_create_record"], ), ], ) config_id = vmcp.config.id mcp_server_url = vmcp.config.mcp_server_url # Before every run: confirm the user's connections are live accounts = scalekit_client.actions.mcp.list_mcp_connected_accounts( config_id=config_id, identifier=IDENTIFIER, include_auth_link=True, ) for account in accounts.connected_accounts: if account.connected_account_status != "ACTIVE": print(f"{account.connection_name} needs auth: {account.authentication_link}") # Then mint a fresh, user-scoped token token = scalekit_client.actions.mcp.create_session_token( mcp_config_id=config_id, identifier=IDENTIFIER, expiry=timedelta(minutes=30), ).token mcp_server = {"url": mcp_server_url, "headers": {"Authorization": f"Bearer {token}"}}

Why this matters for Clay specifically

Clay is a metered surface. Every enrichment spends credits, and a mis-selected tool is not just a wrong answer, it is a charge. Cutting a 40-tool multi-connector surface down to five relevant tools reduces token overhead by roughly 80% and, more importantly for Clay, removes the tools the agent could have called by mistake.

The per-user isolation is the second half. One server definition serves every tenant, and the session token binds each run to one rep's connected accounts. Rep A's agent cannot reach Rep B's Clay workspace or their Salesforce-owned accounts, even though both run against the same endpoint. This is the core challenge of access control for multi-tenant AI agents.

Observability: knowing who spent the credits

Clay's MCP users table tells an admin how many credits a rep consumed. It does not tell your engineering team which agent run triggered which enrichment, or which tool call preceded the bad CRM write.

Every downstream tool call is attributed

Scalekit resolves the authorizing user's credential at request time rather than a shared service account, so each Clay tool call carries a real identity through to the audit record: who triggered it, which connection resolved, which tool ran, and what came back. Scalekit's auth logs expose the authentication side of that chain with filtering by user, organization, method, and status, and stream to your SIEM or warehouse. For a full breakdown of agent tool observability and knowing whether your agent is actually working, the same attribution model applies.

Why a shared key breaks this

A single clay-api-key shared across your agent fleet looks correct in a demo. In production, every enrichment in Clay's usage dashboard resolves to the one person who minted the key, chargeback by team becomes impossible, and the answer to "which customer's agent burned 40,000 credits last Tuesday" is unavailable. Per-user connected accounts make correct attribution the default rather than a reporting project.

Which one to build against

If your agent is interactive, rep-facing, and its work lives in Clay Audiences or ad-hoc account research, build on Clay MCP. Clay maintains the tool surface, credit and Function governance come with the path, and OAuth consent is natural when the user is present.

If your agent runs headless, needs database-wide search, processes more than 100 records per run, or reacts to completion events, build on the Public API and accept a user-scoped static key. Most production GTM systems run both.

The credential layer is identical either way, and Clay's missing per-connection revocation makes it the part most likely to become an incident.

Building a Clay agent? Come compare notes

Clay's MCP surface is moving fast enough that tool inventories and governance behavior change between quarters. If you are shipping a Clay agent and want to compare notes with other builders, join the Scalekit community on Slack.

If you would rather work through your specific auth architecture with an engineer, talk to us directly. Start with the Clay MCP connector docs or browse the Clay MCP connector page.

FAQs

What is the main difference between Clay MCP and the Clay Public API?

Clay MCP is designed for interactive, user-facing agents running inside AI assistants like Claude and ChatGPT. It requires OAuth authentication, exposes Audiences querying and AI account Q&A tools, and enforces per-rep credit budgets. The Public API is for headless backend systems, supports batch runs over JSONL, database-wide structured searches, signed webhooks, and Enterprise table queries, and authenticates with a static clay-api-key header. Neither is a superset of the other.

Can I use Clay MCP for a scheduled background agent?

No. Clay MCP authentication requires a browser session — either via OAuth consent in the hosted server or a clay login session in the local CLI server. Headless execution without a user present cannot complete those flows. Use the Clay Public API for scheduled enrichment syncs, inbound-lead scoring, or any job that runs without a browser.

Why can't I revoke a rep's Clay MCP access directly?

Clay's documented options for removing MCP access are limited to removing the user from the workspace entirely or dropping their credit limit to zero. There is no per-connection kill switch in the MCP users page. This is a revocation gap that your infrastructure must account for separately.

What happens to my API pipeline if the key owner leaves the organization?

The clay-api-key is tied to a specific Clay user. If that user is removed from the workspace, the key stops working and your pipeline fails. Clay does not offer org-scoped or service-account API keys today, so you should monitor for 401 responses and have a key rotation procedure tied to your offboarding workflow.

Does Clay MCP support more than 100 records per run?

No. Batch execution above 100 items per run is only available on the Public API path via presigned JSONL upload and the run-batch endpoint. Clay MCP tools handle individual lookups and small contact lists suited to interactive use cases, not bulk pipelines.

What is the Function/routine/subroutine naming mismatch?

Clay uses three different terms for the same concept depending on context. In the product UI it is called a Function. In the Public API it is a routine, with IDs formatted as function:t_.... In the MCP tool surface it is called a subroutine, surfaced by claymcp_list_subroutines. Budget extra time when mapping between surfaces for the first time.

How does Scalekit handle the N-credential problem for Clay?

Scalekit's Clay MCP connector manages the OAuth flow, per-user token storage, and refresh automatically. For the Public API, a custom connector using Tool Proxy vaults the clay-api-key and injects it at request time, so credentials never enter your agent runtime. Both paths use the same connected-account model, so the MCP vs API choice does not change your auth infrastructure.

What is Virtual MCP and why does it matter for Clay agents?

Virtual MCP is a Scalekit feature that lets you define a single MCP server endpoint exposing only a specific subset of tools from one or more connectors. For Clay, this means you can cut a 16-tool surface down to 3 to 5 tools relevant to a specific agent role, reducing token overhead by roughly 80% and eliminating the risk of the model calling a metered Clay tool by mistake. Each run is bound to a short-lived, per-user session token, enforcing tenant isolation.

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.