conduyt-mcp 4.87.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.
@@ -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;
@@ -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)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "conduyt-mcp",
3
- "version": "4.87.0",
3
+ "version": "4.88.0",
4
4
  "mcpName": "com.conduyt/mcp",
5
5
  "description": "MCP server for Conduyt CRM — expose CRM operations as AI-accessible tools",
6
6
  "type": "module",
@@ -1,11 +1,11 @@
1
1
  {
2
- "generatedAt": "2026-10-13T14:36:32.489Z",
2
+ "generatedAt": "2026-10-15T02:16:36.008Z",
3
3
  "toolCount": 350,
4
- "totalEndpoints": 1080,
4
+ "totalEndpoints": 1084,
5
5
  "counts": {
6
6
  "covered": 309,
7
- "excluded": 321,
8
- "planned": 450,
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"