conduyt-mcp 4.86.0 → 4.88.0
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/dist/tools/contacts.d.ts
CHANGED
|
@@ -9,4 +9,5 @@ export declare const MERGE_TIMEOUT_MS = 75000;
|
|
|
9
9
|
export declare const LOSER_ORDER_NOTE = "losers are merged in the order given: for each field the survivor lacks, the first loser in this order with a value wins; reorder to change precedence; the dry run's filledFields shows which fields will be filled";
|
|
10
10
|
export declare const MERGE_PREVIEW_MAX = 50;
|
|
11
11
|
export declare const MERGE_PREVIEW_TTL_MS: number;
|
|
12
|
+
export declare const EMAIL_LOOKUP_NOTE = "Exact email lookup: one address, or up to 20 distinct addresses in an array. Each is trimmed and lower-cased and matches the contact's primary email OR any secondary email slot (email_2 and up); it is an exact match, not a substring search (use `search` for partial text). Combines with every other filter (AND) inside your account and visibility. An empty or invalid address, or more than 20 distinct addresses, is a 400. On a workspace whose identifier index is still being built, the lookup answers 422 when the stored spellings of the requested addresses exceed its stored-spelling bind budget (a count of spellings, not of contacts; other filters do not help); ask support to complete the identifier backfill. Send addresses once; duplicates collapse.";
|
|
12
13
|
export declare function registerContactTools(server: McpServer, client: ConduytClient): void;
|
package/dist/tools/contacts.js
CHANGED
|
@@ -52,10 +52,14 @@ function createMergePreviewStore() {
|
|
|
52
52
|
drop(key) { rows.delete(key); },
|
|
53
53
|
};
|
|
54
54
|
}
|
|
55
|
+
/** (API ?email=, app main 318adf38d) exact lookup of one address; the API trims and lower-cases, so a stray space is harmless */
|
|
56
|
+
const EMAIL_LOOKUP_ONE = z.string().trim().min(1).max(254);
|
|
57
|
+
export const EMAIL_LOOKUP_NOTE = "Exact email lookup: one address, or up to 20 distinct addresses in an array. Each is trimmed and lower-cased and matches the contact's primary email OR any secondary email slot (email_2 and up); it is an exact match, not a substring search (use `search` for partial text). Combines with every other filter (AND) inside your account and visibility. An empty or invalid address, or more than 20 distinct addresses, is a 400. On a workspace whose identifier index is still being built, the lookup answers 422 when the stored spellings of the requested addresses exceed its stored-spelling bind budget (a count of spellings, not of contacts; other filters do not help); ask support to complete the identifier backfill. Send addresses once; duplicates collapse.";
|
|
55
58
|
export function registerContactTools(server, client) {
|
|
56
59
|
const mergePreviews = createMergePreviewStore();
|
|
57
|
-
server.tool("conduyt_list_contacts", "List and search contacts with filtering. Returns paginated results with name, email, phone, tags, source, and assignee. Each row carries `revision` (integer save revision; pass it back as expectedRevision on conduyt_update_contact or the collaborator tools).", {
|
|
60
|
+
server.tool("conduyt_list_contacts", "List and search contacts with filtering. To find the contact(s) holding a known email address, pass `email` (exact match on the primary or any secondary email); `search` is a substring search. Returns paginated results with name, email, phone, tags, source, and assignee. Each row carries `revision` (integer save revision; pass it back as expectedRevision on conduyt_update_contact or the collaborator tools).", {
|
|
58
61
|
search: z.string().optional().describe("Search by name, email, or phone number"),
|
|
62
|
+
email: z.union([EMAIL_LOOKUP_ONE, z.array(EMAIL_LOOKUP_ONE).min(1).max(20)]).optional().describe(EMAIL_LOOKUP_NOTE),
|
|
59
63
|
tag: z.string().optional().describe("Filter by tag name"),
|
|
60
64
|
source: z.string().optional().describe("Filter by source (e.g. 'signup', 'import', 'manual')"),
|
|
61
65
|
assignedTo: z.string().optional().describe("Filter by assigned user ID"),
|
|
@@ -63,10 +67,13 @@ export function registerContactTools(server, client) {
|
|
|
63
67
|
excludeMasterStatus: z.array(z.string().trim().min(1).max(40)).max(20).optional().describe("Hide contacts whose lead status is one of these — e.g. ['won','lost','abandoned','disqualified'] is the 'Active' view. Naming a status in both lists is a 400."),
|
|
64
68
|
page: z.number().optional().describe("Page number (default 1)"),
|
|
65
69
|
per_page: z.number().optional().describe("Results per page (default 25, max 100)"),
|
|
66
|
-
}, async ({ search, tag, source, assignedTo, masterStatus, excludeMasterStatus, page, per_page }) => {
|
|
70
|
+
}, async ({ search, email, tag, source, assignedTo, masterStatus, excludeMasterStatus, page, per_page }) => {
|
|
67
71
|
const params = new URLSearchParams();
|
|
68
72
|
if (search)
|
|
69
73
|
params.set("search", search);
|
|
74
|
+
// repeated `email` params, one per address (the API reads every occurrence); an omitted or empty array sends none
|
|
75
|
+
for (const address of email === undefined ? [] : Array.isArray(email) ? email : [email])
|
|
76
|
+
params.append("email", address);
|
|
70
77
|
if (tag)
|
|
71
78
|
params.set("tag", tag);
|
|
72
79
|
if (source)
|
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
2
|
import { ConduytClient } from "../client.js";
|
|
3
|
+
export declare const SMART_VIEW_ICON_IDS: readonly ["heart", "star", "trophy", "badge", "target", "eye", "clock", "hourglass", "siren", "bolt", "fire", "rain", "funnel", "pyramid", "flag", "pin", "push-pin", "thumbs-up", "thumbs-down", "coffee", "rocket", "number-1", "number-2", "number-3", "number-4", "number-5", "number-6", "number-7", "number-8", "number-9"];
|
|
3
4
|
export declare function registerSavedFilterTools(server: McpServer, client: ConduytClient): void;
|
|
@@ -26,6 +26,14 @@ const filtersSchema = z
|
|
|
26
26
|
.union([z.array(groupSchema).max(10), z.array(ruleSchema).max(20)])
|
|
27
27
|
.optional()
|
|
28
28
|
.describe('Grouped filter payload (max 10 groups × 20 rules), e.g. [{"conjunction":"AND","rules":[{"field":"source","operator":"equals","value":"facebook"}]}]. A flat rule array is also accepted and saved as a single AND group. Omit for an empty filter set.');
|
|
29
|
+
// The 30 current Smart View icon ids in picker order (app branch fable/smart-view-icons: public/smart-view-icons/manifest.json,
|
|
30
|
+
// lib/smart-view-icons.ts). The 17 legacy ids the API still accepts as deprecated inputs are deliberately NOT advertised here.
|
|
31
|
+
export const SMART_VIEW_ICON_IDS = [
|
|
32
|
+
"heart", "star", "trophy", "badge", "target", "eye", "clock", "hourglass", "siren", "bolt",
|
|
33
|
+
"fire", "rain", "funnel", "pyramid", "flag", "pin", "push-pin", "thumbs-up", "thumbs-down", "coffee",
|
|
34
|
+
"rocket", "number-1", "number-2", "number-3", "number-4", "number-5", "number-6", "number-7", "number-8", "number-9",
|
|
35
|
+
];
|
|
36
|
+
const iconSchema = (omitted) => z.enum(SMART_VIEW_ICON_IDS).optional().describe(`The view's icon, one of: ${SMART_VIEW_ICON_IDS.join(", ")}. ${omitted}. This tool accepts current ids only.`);
|
|
29
37
|
export function registerSavedFilterTools(server, client) {
|
|
30
38
|
server.tool("conduyt_list_saved_filters", "List YOUR saved contact filters (the web app's 'Saved' dropdown on All Contacts). Each entry has a name, the grouped filter payload, and sort. Saved filters are personal to the API key's user. Requires the 'saved-filters' scope.", {
|
|
31
39
|
entity_type: z.enum(["contact"]).optional().describe("Entity type (default 'contact')"),
|
|
@@ -43,11 +51,12 @@ export function registerSavedFilterTools(server, client) {
|
|
|
43
51
|
sortField: z.string().optional().describe("Sort field applied with the filter (default createdAt)"),
|
|
44
52
|
sortOrder: z.enum(["asc", "desc"]).optional().describe("Sort direction (default desc)"),
|
|
45
53
|
entityType: z.enum(["contact"]).optional().describe("Entity type (default 'contact')"),
|
|
54
|
+
icon: iconSchema("Omitted: default heart"),
|
|
46
55
|
}, async (params) => {
|
|
47
56
|
// (Smart Views 09-24) saved filters are personal Smart Views now: the same body creates one (personal for a
|
|
48
57
|
// rep key; an admin key creates a SHARED view, admins have no private filters); POST /saved-filters is retired (410)
|
|
49
58
|
// personal: true keeps the saved-filter contract for EVERY key (an admin key creates a private view, never a shared one)
|
|
50
|
-
const result = await client.post("/api/v1/smart-views", { name: params.name, filters: params.filters, sortField: params.sortField, sortOrder: params.sortOrder, personal: true });
|
|
59
|
+
const result = await client.post("/api/v1/smart-views", { name: params.name, filters: params.filters, sortField: params.sortField, sortOrder: params.sortOrder, icon: params.icon, personal: true });
|
|
51
60
|
return formatResult(result);
|
|
52
61
|
});
|
|
53
62
|
server.tool("conduyt_update_saved_filter", "Rename a saved filter (a personal Smart View) or replace its filters/sort. Owner-only — a personal view is its owner's for every role. Use conduyt_list_saved_filters or conduyt_list_smart_views to find the id. Requires the 'saved-filters' scope.", {
|
|
@@ -56,7 +65,8 @@ export function registerSavedFilterTools(server, client) {
|
|
|
56
65
|
filters: filtersSchema,
|
|
57
66
|
sortField: z.string().optional(),
|
|
58
67
|
sortOrder: z.enum(["asc", "desc"]).optional(),
|
|
59
|
-
|
|
68
|
+
icon: iconSchema("Omitted: unchanged"),
|
|
69
|
+
}, async ({ id, name, filters, sortField, sortOrder, icon }) => {
|
|
60
70
|
// Inline body (undefined fields drop out in JSON) — keeps the shape
|
|
61
71
|
// readable by the contract verifier's static parser.
|
|
62
72
|
const result = await client.patch(`/api/v1/smart-views/${encodeURIComponent(id)}`, {
|
|
@@ -64,6 +74,7 @@ export function registerSavedFilterTools(server, client) {
|
|
|
64
74
|
filters,
|
|
65
75
|
sortField,
|
|
66
76
|
sortOrder,
|
|
77
|
+
icon,
|
|
67
78
|
});
|
|
68
79
|
return formatResult(result);
|
|
69
80
|
});
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
|
-
"generatedAt": "2026-10-
|
|
2
|
+
"generatedAt": "2026-10-15T02:16:36.008Z",
|
|
3
3
|
"toolCount": 350,
|
|
4
|
-
"totalEndpoints":
|
|
4
|
+
"totalEndpoints": 1084,
|
|
5
5
|
"counts": {
|
|
6
6
|
"covered": 309,
|
|
7
|
-
"excluded":
|
|
8
|
-
"planned":
|
|
7
|
+
"excluded": 323,
|
|
8
|
+
"planned": 452,
|
|
9
9
|
"uncategorized": 0
|
|
10
10
|
},
|
|
11
11
|
"matrix": {
|
|
@@ -1941,6 +1941,10 @@
|
|
|
1941
1941
|
"status": "excluded",
|
|
1942
1942
|
"reason": "CRON_SECRET-gated infrastructure jobs; never key-callable"
|
|
1943
1943
|
},
|
|
1944
|
+
"GET /api/v1/cron/recover-attachment-ledgers": {
|
|
1945
|
+
"status": "excluded",
|
|
1946
|
+
"reason": "CRON_SECRET-gated infrastructure jobs; never key-callable"
|
|
1947
|
+
},
|
|
1944
1948
|
"GET /api/v1/cron/recover-booking-side-effects": {
|
|
1945
1949
|
"status": "excluded",
|
|
1946
1950
|
"reason": "CRON_SECRET-gated infrastructure jobs; never key-callable"
|
|
@@ -1957,6 +1961,10 @@
|
|
|
1957
1961
|
"status": "excluded",
|
|
1958
1962
|
"reason": "CRON_SECRET-gated infrastructure jobs; never key-callable"
|
|
1959
1963
|
},
|
|
1964
|
+
"GET /api/v1/cron/release-google-grants": {
|
|
1965
|
+
"status": "excluded",
|
|
1966
|
+
"reason": "CRON_SECRET-gated infrastructure jobs; never key-callable"
|
|
1967
|
+
},
|
|
1960
1968
|
"GET /api/v1/cron/reply-capture-drain": {
|
|
1961
1969
|
"status": "excluded",
|
|
1962
1970
|
"reason": "CRON_SECRET-gated infrastructure jobs; never key-callable"
|
|
@@ -3227,10 +3235,18 @@
|
|
|
3227
3235
|
"status": "planned",
|
|
3228
3236
|
"reason": "lead routing rule management"
|
|
3229
3237
|
},
|
|
3238
|
+
"GET /api/v1/mailbox/callback/google": {
|
|
3239
|
+
"status": "planned",
|
|
3240
|
+
"reason": "mailbox sync surfaces"
|
|
3241
|
+
},
|
|
3230
3242
|
"GET /api/v1/mailbox/callback/microsoft": {
|
|
3231
3243
|
"status": "planned",
|
|
3232
3244
|
"reason": "mailbox sync surfaces"
|
|
3233
3245
|
},
|
|
3246
|
+
"POST /api/v1/mailbox/connect/google": {
|
|
3247
|
+
"status": "planned",
|
|
3248
|
+
"reason": "mailbox sync surfaces"
|
|
3249
|
+
},
|
|
3234
3250
|
"POST /api/v1/mailbox/connect/microsoft": {
|
|
3235
3251
|
"status": "planned",
|
|
3236
3252
|
"reason": "mailbox sync surfaces"
|