
Your agent needs to work in Close. It needs to pull the pipeline before a call, log what happened after, and nudge stalled opportunities overnight. Close ships a hosted MCP server and a REST API that has been production-grade for years, and Scalekit exposes both as separate connectors. They are not interchangeable. The gap is not capability breadth; it is write semantics and event handling. Here is how to pick.
Both paths sit on the same Close organization and the same OAuth authorization server. What differs is the surface each one presents to an agent and the credential each one will accept.
Close runs a hosted Model Context Protocol (MCP) server at mcp.close.com/mcp, maintained by Close. Transport is Streamable HTTP; Server-Sent Events is not supported. Authentication is OAuth 2.0 with Dynamic Client Registration (DCR), or a static API key passed through the Close-API-Key and Close-Scope request headers.
Tools are tiered by the Close-Scope value. At the time of writing, Close's tool reference lists 67 read-only tools under mcp.read, 16 more under mcp.write_safe, and 34 more under mcp.write_destructive. Each higher scope includes everything below it.
Official docs: Close MCP Server and Close MCP Tools.
The Close REST API is a conventional JSON interface at api.close.com/api/v1. It covers leads, contacts, opportunities, activities, webhooks, the 30-day event log, bulk actions, exports, reporting, sequences, and org configuration.
Authentication accepts two credential types: an API key over HTTP Basic Auth, with the key as the username and an empty password, or an OAuth 2.0 bearer token. Rate limits are enforced per endpoint group, with a per-key limit and a wider organization limit.
Official docs: Close API Overview.
The overlap on core CRM objects is nearly total. Both paths create leads, update opportunities, manage tasks, and read activity history. The divergence starts the moment your agent tries to send something, react to something, or operate on thousands of records at once.
The single most consequential gap is send semantics. closemcp_create_draft_email explicitly saves an unsent draft for the user to review and send from Close. There is no tool that dispatches it. There is no SMS creation tool at all, only SMS template management.
For a human-in-the-loop assistant, that is a feature. A drafting agent cannot accidentally email a prospect. For an autonomous outbound sequencer, it is a hard blocker, and no configuration flag changes it.
The second gap is reactivity. The MCP server has no webhook tools, so an agent on the MCP path cannot subscribe to opportunity status changes; it can only poll. Bulk actions, export jobs, lead merge, and logging calls placed by an external dialer are likewise REST-only.
The gap runs both directions, which is unusual in this series. closemcp_search takes a query like "leads with an active opportunity over $500" and resolves it server-side, while the REST equivalent requires you to construct an Advanced Filtering query object yourself.
closemcp_aggregation answers counting questions across leads, contacts, opportunities, and activities in one call, after a required closemcp_get_fields lookup. Voice agent tooling is MCP-only: your agent can list configured voice agents, dispatch one to call a contact, and pull performance reports. Billing reads such as closemcp_get_billing_summary and closemcp_get_ai_credit_usage have no REST counterpart either.
There is also closemcp_close_product_knowledge_search, which queries Close's own documentation. A support or onboarding agent can answer "how do I set up automated lead assignment" without you building a retrieval pipeline over Close's help center.
This is where Close breaks the usual pattern. On most tools in this series, MCP means OAuth and the API means credential choice. Close inverts part of that, and the inversion has real consequences for how you scope an agent.
The recommended path is OAuth 2.0 with Dynamic Client Registration, which is what Claude, Cursor, ChatGPT, and other MCP clients use. For custom setups, Close documents an alternative: send your API key in Close-API-Key and a scope tier in Close-Scope.
That second option is why "MCP cannot run headless" is false for Close. A nightly job can hold an API key and a mcp.read header and never touch a browser. Whether it should is a separate question, addressed below.
The REST API accepts an API key over HTTP Basic Auth or an OAuth bearer token. The OAuth token response returns "scope": "all.full_access offline_access", and Close's documented authorization request carries no scope parameter at all.
Scalekit's Close connector docs confirm this: Close OAuth apps automatically receive all.full_access and offline_access, with no additional scope configuration. There is no read-only OAuth grant for the REST API.
Read those two sections together and the practical result is clear. On the MCP path you can hand an agent a read-only credential. On the REST path you cannot; every OAuth token is a full-access token, and every API key inherits its owner's permissions.
That does not make the REST API unusable for least privilege. It moves the enforcement point. If the credential cannot be narrowed, the tool surface has to be, which is exactly what a virtual MCP server does: it declares which connections and which specific tools an agent role can see, independent of what the underlying token permits.
Close manages the MCP server and the API. Everything downstream of the credential is yours, and three specific behaviors will bite an agent that was only tested with one user.
Close access tokens carry expires_in: 3600. Refresh requires the offline_access scope, and Close's documentation is explicit that the authorization server issues a new refresh token on every refresh and revokes the old one immediately.
For a single-threaded script this is unremarkable. For an agent runtime it is a race condition waiting to happen: two workers detect an expired token at the same moment, both call /oauth2/token/, one wins, and the loser writes a refresh token that Close has already revoked. That user is now disconnected and must re-authorize, with no error surfaced until the next tool call. This is the same class of problem covered in handling token refresh for AI agents.
Close enforces limits per endpoint group, not globally. There is a per-API-key limit and a wider organization limit, documented as three times the per-key limit, shared across all users' keys in that organization.
Your agent is therefore competing with the customer's Zapier automations, their data warehouse sync, and their other integrations for the same budget. Handle 429 by reading the RateLimit header and sleeping for the reset value, and treat rate-limit headroom as a property of the tenant rather than of your service.
The OAuth token response includes an organization_id and a user_id. The credential is bound to the organization the user selected on the consent screen, not to the user's full account.
Close's own MCP documentation makes the consequence explicit: to work with more than one Close organization you add a separate connection per organization, each with its own name. For a B2B agent whose customers run multiple Close orgs, the unit of credential isolation is the user and organization pair, not the user.
Most production Close agents end up using both, because the two surfaces answer different questions. The split below is about the job the agent does, not about how quickly you want to ship.
Scalekit ships both paths as separate connectors, and this is the practical reason to run Close through it. The Close connector wraps the REST API with 103 tools prefixed close_. The Close MCP connector proxies Close's own server with tools prefixed closemcp_. Same SDK, same connected account model, same execute_tool call.
Install the SDK and the framework you are building against. This walkthrough uses LangChain in Python.
A connected account is the per-user credential record. Create or fetch it first, and send the user through consent only if it is not already ACTIVE. The connection_name values below must match the connection names configured in your Scalekit dashboard exactly; this is the most common integration error.
Scalekit stores the resulting access and refresh tokens and refreshes them against the one-hour expiry using the offline_access grant. The rotation race described earlier is handled in one place rather than in every worker.
Before the agent loop, fetch the tool surface. list_scoped_tools does not return a flat catalog of everything Close can do; it returns the tools the current user's connected account is authorized to call. That distinction is what separates a per-user agent from a shared-credential agent.
For LangChain, Scalekit returns native tool objects, so no schema reshaping is needed. This agent works the REST surface, where writes actually dispatch. Understanding how LangChain tool calling works helps clarify why the integration is seamless here.
Subscribing to change events is a REST-only capability, and it is one call through the same connected account. Note that events is passed as a JSON-encoded string.
Nothing about the calling convention changes when you switch paths. The same execute_tool method, the same identifier, a different connection_name. Here the agent uses MCP for the natural-language query it is better at, then drafts an email for human review.
Hi Jane,
Circling back on the pricing question.
", }, ) print(search.data, draft.data)Handing an agent every tool from both connectors is the wrong default. A virtual MCP server declares which connections and which specific tools a given agent role can see, then mints a short-lived session token bound to one user before each run. The default token expiry is about an hour, and create_session_token is the remint call.
Generate the per-user URL on your backend. Never share one URL across users, since each is pre-authenticated for a single identity.
Any MCP-capable framework consumes that URL directly. Mastra discovers the tool list and schemas automatically.
This is where the permission inversion gets resolved. The REST connector's token is all.full_access and cannot be narrowed at Close; the virtual MCP server narrows what the agent can reach with it, and does so per agent role rather than per credential. It also cuts context cost, since a server scoped to eight tools does not spend thousands of tokens describing 103.
Every tool call through Scalekit is recorded with full attribution: who authorized the connection, which agent ran the call, which tool, and what came back. Those agent auth logs are queryable and exportable to your SIEM.
For a Close agent this matters more than usual. When a rep asks why an opportunity changed stage at 2am, "the automation did it" is not an answer a sales leader accepts. More on the reasoning in agent tool observability.
Both paths hand you a credential per user. Neither hands you a vault, a rotation strategy, or a revocation flow.
In a multi-tenant B2B agent, every customer user has their own Close credential. Fifty reps across eight customer organizations is fifty tokens to encrypt at rest, isolate per tenant, refresh before the 3600-second expiry, and invalidate when someone leaves.
Close's refresh token rotation makes the storage requirement stricter than most: the stored refresh token is single-use, so a write that loses a race silently disconnects a user. The API key alternative avoids refresh entirely, which is precisely why it is tempting and precisely why it is wrong for multi-tenant use. A Close API key is a long-lived static secret with no expiry, no per-agent attribution, and no clean revocation story when an employee offboards. The broader implications of secure token management for AI agents at scale apply directly here.
Scalekit's Close connectors handle the OAuth flow, encrypted per-user token storage, and automatic refresh for both the REST path and the MCP path. The MCP versus API decision changes which tools your agent can call. It does not change your auth infrastructure.
Related reading: access control for multi-tenant AI agents and single vs multi-tenant tool calling agent auth.
If your agent reads, reasons, and drafts for a human to approve, build against Close MCP. The mcp.read tier gives you a genuinely read-only credential, natural-language search removes a layer of query construction, and the draft-only write semantics are a safety property rather than a limitation.
If your agent sends, reacts, or operates at volume, build against the Close API. Outbound email and SMS, webhook subscriptions, bulk actions, exports, and external call logging have no MCP equivalent, and will not get one by waiting.
Most teams ship both: MCP behind the in-app assistant, REST behind the overnight pipeline. The decision worth making deliberately is not which path, but where least privilege gets enforced, because on Close the REST credential cannot enforce it for you.
Browse the Scalekit Close connector, or start from a working pattern with the CRM AI agent, outbound prospecting agent, and deal intelligence agent templates. The full catalog of GTM and RevOps agent templates covers adjacent workflows, and every connector in the catalog is listed in the AgentKit connector docs.
Building on Close and hitting something this post did not cover? Join the Scalekit Slack community and ask, or talk to us for help wiring it up. Usage and limits are on the pricing page.