@adrata/adrata-mcp 1.0.46 → 1.0.49
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/server.js +20 -4
- package/server.json +2 -2
- package/tools/provisioning/onboarding-tools.js +54 -21
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adrata/adrata-mcp",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.49",
|
|
4
4
|
"description": "Adrata MCP Server \u2014 connect Claude Code, Codex, Gemini, Cursor, and other AI tools to your CRM. About 275 tools registered at startup for companies, people, deals, actions, buyer groups, warm intros, webhooks and intelligence, plus 65 more behind eight named toolsets you load with enable_toolset.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "server.js",
|
package/server.js
CHANGED
|
@@ -1828,14 +1828,30 @@ server.tool('get_company_firmographics', 'Get employee count and revenue metadat
|
|
|
1828
1828
|
{ companyId: z.string() },
|
|
1829
1829
|
async (a) => ok(await api('GET', `/api/v1/companies/${a.companyId}/firmographics`)));
|
|
1830
1830
|
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1831
|
+
// `enrichPhone` and `forceRefresh` reach the route ONLY through the request
|
|
1832
|
+
// body, and this tool used to send none at all — no `body` key, so the POST went
|
|
1833
|
+
// out empty and the route's `enrich_phone` fell to its `unwrap_or(false)`
|
|
1834
|
+
// default on every call. The flag was therefore unreachable from MCP: an agent
|
|
1835
|
+
// could pass it, the schema would accept it, and no vendor was ever asked for a
|
|
1836
|
+
// phone. That is the "capability that nothing can reach" shape, and it is the
|
|
1837
|
+
// reason phone was never requested on any of the async jobs in production.
|
|
1838
|
+
server.tool('enrich_person', `Trigger enrichment for a person — email, phone, professional info, social profiles. SPENDS VENDOR CREDITS. Phone is a separate paid field (a BetterContact mobile is 10 credits against 1 for an email), so pass enrichPhone: true whenever the ask is for a mobile, cell, direct line or "contact details" — without it no vendor is asked for a number and the run still reports success.${governedWriteNote('write:people')}`,
|
|
1839
|
+
{
|
|
1840
|
+
personId: z.string(),
|
|
1841
|
+
enrichPhone: z.boolean().optional().describe('Also look up a mobile/direct phone. Paid field, explicit opt-in, defaults false.'),
|
|
1842
|
+
forceRefresh: z.boolean().optional().describe('Run even when fields are already populated; only for an explicitly stale or wrong record.'),
|
|
1843
|
+
...governedWriteArgs,
|
|
1844
|
+
},
|
|
1845
|
+
async ({ personId, enrichPhone, forceRefresh, ...g }) => runGovernedWrite(
|
|
1834
1846
|
g,
|
|
1835
1847
|
{
|
|
1836
1848
|
method: 'POST',
|
|
1837
1849
|
path: `/api/v1/people/${personId}/enrich`,
|
|
1838
|
-
|
|
1850
|
+
body: body({ enrichPhone, forceRefresh }),
|
|
1851
|
+
preview: {
|
|
1852
|
+
entity: 'person', entityId: personId, operation: 'enrich',
|
|
1853
|
+
spendsVendorCredits: true, enrichPhone: enrichPhone === true,
|
|
1854
|
+
},
|
|
1839
1855
|
},
|
|
1840
1856
|
));
|
|
1841
1857
|
|
package/server.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"name": "com.adrata/adrata-mcp",
|
|
4
4
|
"description": "Adrata revenue-intelligence MCP server: companies, people, opportunities, actions, buyer groups, enrichment, email, and workspace operations for AI agents.",
|
|
5
5
|
"status": "active",
|
|
6
|
-
"version": "1.0.
|
|
6
|
+
"version": "1.0.49",
|
|
7
7
|
"websiteUrl": "https://adrata.com/developers",
|
|
8
8
|
"repository": {
|
|
9
9
|
"url": "https://github.com/adrata/adrata",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"registryType": "npm",
|
|
16
16
|
"registryBaseUrl": "https://registry.npmjs.org",
|
|
17
17
|
"identifier": "@adrata/adrata-mcp",
|
|
18
|
-
"version": "1.0.
|
|
18
|
+
"version": "1.0.49",
|
|
19
19
|
"transport": {
|
|
20
20
|
"type": "stdio"
|
|
21
21
|
},
|
|
@@ -392,6 +392,42 @@ export function validateOnboardingArgs(args = {}) {
|
|
|
392
392
|
return problems;
|
|
393
393
|
}
|
|
394
394
|
|
|
395
|
+
/**
|
|
396
|
+
* Whether the adaptive payload (launch, preparedAccountIds, preparedNote,
|
|
397
|
+
* source) is durable, read FROM the invite response rather than assumed. The
|
|
398
|
+
* route returns `recorded` alongside `inviteUrl`: `true` means the
|
|
399
|
+
* workspace_invitation_records row exists; `false` means the link works but
|
|
400
|
+
* the record was not written. An absent `recorded` is reported as unknown —
|
|
401
|
+
* `null` — rather than asserted either way.
|
|
402
|
+
*/
|
|
403
|
+
export function describeAdaptivePayloadDurability(payload = {}) {
|
|
404
|
+
const recorded = payload?.recorded;
|
|
405
|
+
if (recorded === true) {
|
|
406
|
+
return {
|
|
407
|
+
adaptivePayloadDurable: true,
|
|
408
|
+
adaptivePayloadNote:
|
|
409
|
+
'The seat and the link are live, and the launch, preparedAccountIds, preparedNote and source'
|
|
410
|
+
+ ' were stored with the invitation (recorded: true).',
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
if (recorded === false) {
|
|
414
|
+
return {
|
|
415
|
+
adaptivePayloadDurable: false,
|
|
416
|
+
adaptivePayloadNote:
|
|
417
|
+
'The seat and the link are live, but the endpoint reported recorded: false — the invitation'
|
|
418
|
+
+ ' record carrying launch, preparedAccountIds, preparedNote and source was not written, so it'
|
|
419
|
+
+ ' will not appear in the issued list and cannot be revoked from it.',
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
return {
|
|
423
|
+
adaptivePayloadDurable: null,
|
|
424
|
+
adaptivePayloadNote:
|
|
425
|
+
'The seat and the link are live. The endpoint did not confirm whether the invitation record'
|
|
426
|
+
+ ' carrying launch, preparedAccountIds, preparedNote and source was written (no `recorded`'
|
|
427
|
+
+ ' field in the response), so durability is unknown rather than asserted.',
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
|
|
395
431
|
/** The exact body this tool would send. Kept in one place so preview and live write cannot drift. */
|
|
396
432
|
export function buildInvitationBody(args = {}) {
|
|
397
433
|
const body = {
|
|
@@ -404,19 +440,19 @@ export function buildInvitationBody(args = {}) {
|
|
|
404
440
|
if (args.managerId) body.managerId = args.managerId;
|
|
405
441
|
|
|
406
442
|
// ── The adaptive payload ────────────────────────────────────────────────
|
|
407
|
-
//
|
|
408
|
-
//
|
|
409
|
-
// `
|
|
410
|
-
//
|
|
411
|
-
//
|
|
412
|
-
//
|
|
413
|
-
// the
|
|
414
|
-
//
|
|
415
|
-
// second edit when it lands.
|
|
443
|
+
// These four fields are stored by the deployed endpoint. `InviteMemberRequest`
|
|
444
|
+
// in `code/api/src/routes/v1/entities/org/workspace/members.rs` declares
|
|
445
|
+
// `launch`, `prepared_account_ids`, `prepared_note` and `source` with
|
|
446
|
+
// `#[serde(default)]` (camelCase via `alias`), and `mint_workspace_invitation`
|
|
447
|
+
// in `invitations.rs` binds them into `workspace_invitation_records`. The
|
|
448
|
+
// route answers with `recorded: true|false` saying whether that durable row
|
|
449
|
+
// was written, and the live-write result below reports durability FROM that
|
|
450
|
+
// field rather than from an assumption about what the server does.
|
|
416
451
|
//
|
|
417
|
-
//
|
|
418
|
-
//
|
|
419
|
-
//
|
|
452
|
+
// (History: until 2026-09-06 the endpoint accepted only email, role and
|
|
453
|
+
// managerId and dropped the rest; the tool then said so in its response.
|
|
454
|
+
// That note outlived the fix and told an AE a stored configuration was not
|
|
455
|
+
// durable — hence the rule above: report what the response says.)
|
|
420
456
|
//
|
|
421
457
|
// Note also that `InviteMemberRequest` carries no
|
|
422
458
|
// `#[serde(rename_all = "camelCase")]` — `manager_id` works only because it
|
|
@@ -625,12 +661,12 @@ export function registerProvisioningTools(
|
|
|
625
661
|
preparedAccountIds: body.preparedAccountIds ?? [],
|
|
626
662
|
preparedAccountCount: body.preparedAccountIds?.length ?? 0,
|
|
627
663
|
preparedNote: body.preparedNote ?? null,
|
|
628
|
-
adaptivePayloadDurable:
|
|
664
|
+
adaptivePayloadDurable: null,
|
|
629
665
|
adaptivePayloadNote:
|
|
630
|
-
'
|
|
631
|
-
+ '
|
|
632
|
-
+ ' and
|
|
633
|
-
+ '
|
|
666
|
+
'Not known until minted. The invite endpoint stores launch, preparedAccountIds, preparedNote'
|
|
667
|
+
+ ' and source with the invitation (members.rs InviteMemberRequest → invitations.rs'
|
|
668
|
+
+ ' mint_workspace_invitation) and reports `recorded` on the live write; the live result'
|
|
669
|
+
+ ' carries that answer.',
|
|
634
670
|
preview: validation,
|
|
635
671
|
body,
|
|
636
672
|
note:
|
|
@@ -712,10 +748,7 @@ export function registerProvisioningTools(
|
|
|
712
748
|
inviteUrl,
|
|
713
749
|
launch: body.launch ?? null,
|
|
714
750
|
preparedAccountIds: body.preparedAccountIds ?? [],
|
|
715
|
-
|
|
716
|
-
adaptivePayloadNote:
|
|
717
|
-
'The seat and the link are live. launch/preparedAccountIds/preparedNote were sent but the'
|
|
718
|
-
+ ' deployed endpoint does not yet store them — see the integration point in tools/provisioning.js.',
|
|
751
|
+
...describeAdaptivePayloadDurability(payload),
|
|
719
752
|
credentialWarning:
|
|
720
753
|
'inviteUrl is a credential: anyone holding it can seat themselves in this workspace. Deliver it'
|
|
721
754
|
+ ' over a trusted channel and do not paste it into a log, a ticket, or a shared document.',
|