Everything on this page touches Engage — the people who have filled in a form, been imported, or been created by hand, and the accounts they belong to. Two things make it different from the rest of the MCP surface. Writes here are not drafts: a contact you edit through a connected AI client is edited immediately, in live CRM data, with no publish step in between. And your plan’s contact cap silently narrows what these tools can see.
All eight tools gate on the contact:read and contact:write privileges, and their RBAC overrides must be scoped to the contact resource specifically: an override that made you an editor on a page type does not satisfy a contact gate. All eight are also available in the Leed Assistant.
Contacts
list_engage_contacts
GET /api/engage/contacts · Returns { contacts, total, totalAll, stageCounts }
| Parameter | Type | Required | Default | Notes |
|---|---|---|---|---|
search | string | No | — | Free-text match over first name, last name, email and title |
limit | integer, 1–100 | No | 50 | Page size |
offset | integer, ≥ 0 | No | 0 | Rows to skip |
Contacts come back sorted by readiness, highest first, with unscored contacts last and the contact id as a stable tiebreak so paging is consistent. Each row carries the contact’s profile, the account it is linked to, its joined engage score (or null when unscored) and an optedOut flag for anyone whose most recent opt record is a do-not-contact.
stageCounts is a four-key breakdown — awareness, consideration, evaluation, decision — of the scored contacts inside the current search, and is always present with zeros rather than omitted.
get_engage_contact
GET /api/engage/contacts/:id · Returns { contact }
| Parameter | Type | Required | Default | Notes |
|---|---|---|---|---|
id | integer | Yes | — | The contact id from list_engage_contacts |
A contact that does not exist, belongs to another workspace, or sits outside your plan’s visible window all return the same 404. That is deliberate: a locked contact’s existence is never confirmed.
create_contact
POST /api/leaddetails/create · Returns 201 with { leadDetailsId }
| Parameter | Type | Required | Default | Notes |
|---|---|---|---|---|
email | email address | Yes | — | The natural key, together with your workspace |
firstName | string | No | — | — |
lastName | string | No | — | — |
title | string | No | — | Job title — also what persona matching reads |
phone | string | No | — | — |
country | string | No | — | — |
The email domain is derived server-side, and a genuinely new contact is stamped with the source manual.
update_contact
PUT /api/leaddetails/:leadDetailsId · Returns { leadDetail }
| Parameter | Type | Required | Default | Notes |
|---|---|---|---|---|
leadDetailsId | integer | Yes | — | Which contact to edit |
firstName | string or null | No | unchanged | — |
lastName | string or null | No | unchanged | — |
title | string or null | No | unchanged | — |
phone | string or null | No | unchanged | — |
linkedinUrl | string or null | No | unchanged | — |
country | string or null | No | unchanged | — |
timezone | string or null | No | unchanged | Validated against the runtime’s IANA zone set; a bad value is stored as null, not rejected |
leadCompaniesId | integer or null | No | unchanged | The account to link to; null detaches the contact |
Email is not editable. It is the natural key, and there is no tool that changes it. An empty string clears a field, which is worth stating to a model explicitly — "" is a deletion, not a no-op.
total versus totalAll
Both counts come back on every list_engage_contacts response, and the difference is not what most readers first assume:
| Field | Counts | Affected by search? | Affected by your contact cap? |
|---|---|---|---|
total | Contacts matching the current search | Yes | Yes |
totalAll | Contacts ignoring the current search | No | Yes |
With no search, the two are equal. totalAll is the “of how many” number for a filtered view, not an uncapped grand total:
{
"contacts": [ "…12 rows…" ],
"total": 12,
"totalAll": 250,
"stageCounts": { "awareness": 5, "consideration": 4, "evaluation": 3, "decision": 0 }
}The window is the oldest contacts you own, ordered by creation date. So the contacts that get locked as you grow past your cap are the newest arrivals — the ones a model is most likely to be looking for.
| Plan | Contacts visible |
|---|---|
| Free | 250 |
| Starter | 1,000 |
| Growth | 10,000 |
| Enterprise | unlimited |
Those are the launch defaults; a workspace’s own stored quota is what actually applies. Contacts covers the contact record itself, its sources, and the saved views the CMS builds on the same data.
Accounts
An account is a company: firmographics, a link to the contacts who work there, and a rolled-up score.
list_engage_accounts
GET /api/engage/accounts · Returns { accounts }
Takes no parameters. Every account for the workspace comes back with its firmographic fields and its persisted score — readiness, fit, intent and journey stage — or score: null when the account has never been scored.
update_engage_account
PUT /api/engage/accounts/:id · Returns { account }, or 404 if there is no such account
| Parameter | Type | Required | Default | Notes |
|---|---|---|---|---|
id | integer | Yes | — | Which account to edit |
name | string | No | unchanged | Cannot be cleared — it is the display key |
industry | string or null | No | unchanged | — |
url | string or null | No | unchanged | — |
size | integer ≥ 0, or null | No | unchanged | Headcount |
revenue | number ≥ 0, or null | No | unchanged | — |
currentCustomer | boolean | No | unchanged | Accepts true/false, never null |
sicCodes | string or null | No | unchanged | — |
address, address2, city, state, postalCode, country | string or null | No | unchanged | Postal address |
purchasedProducts | string or null | No | unchanged | — |
competitiveProducts | string or null | No | unchanged | — |
Only the fields you send change; a nullable field accepts an explicit null to clear it. Accounts is the same record seen from the Engage screens.
currentCustomer is the Docs MCP gate
Scores
get_engage_scores
GET /api/engage/scores · Returns { score } or { scores }
| Parameter | Type | Required | Default | Notes |
|---|---|---|---|---|
contactId | integer | No | — | Return this contact’s score as { score } |
accountId | integer | No | — | Return this account’s score as { score } |
Send neither and you get every score for the workspace as { scores }. A subject with no score yet returns { score: null } rather than a 404.
recompute_engage_scores
POST /api/engage/scores/recompute · Returns { recomputed } — the number of contacts scored
Takes no parameters, and it is idempotent: running it twice in a row produces the same numbers. Note that it gates on ai:write, not on contact:write like everything else on this page, so a role that can edit contacts is not automatically a role that can recompute them. The Privilege Matrix shows the minimum role that carries it.
Scores are never computed per request
A read returns whatever was last persisted. Nothing is recalculated because you asked for it, which is why a contact created a minute ago comes back with score: null rather than a freshly derived number — it has not been scored yet.
recompute_engage_scores is what changes that, and it rewrites every contact and account score for the workspace from current signals: profile completeness, email domain, source, opens and clicks, and title-to-persona matching. It is not a targeted operation, so a model should not reach for it after every small edit. One useful rule: run it after deleting or reworking a persona, because persona assignments are only rewritten by a recompute. What each of readiness, fit, intent, journey stage and persona match actually measures is in Engage Scores.
There is no delete
Contacts and accounts cannot be deleted through MCP, and there is no delete tool for either of them in the Leed Assistant either — unlike pages, forms, personas and campaigns, which have destructive tools that exist but are hidden from MCP. Nothing on this surface removes a contact record. Removal is a CMS action.
If the tool name you came here for is not on this page, the Operator MCP Tool Index lists every tool alphabetically with the page that documents its parameters.