conduyt-mcp 4.34.0 → 4.35.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/index.js +2 -0
- package/dist/tools/reports.d.ts +3 -0
- package/dist/tools/reports.js +105 -0
- package/package.json +1 -1
- package/scripts/coverage-matrix.json +27 -13
package/dist/index.js
CHANGED
|
@@ -41,6 +41,7 @@ import { registerLifecycleTools } from "./tools/lifecycle.js";
|
|
|
41
41
|
import { registerReplyCaptureTools } from "./tools/reply-capture.js";
|
|
42
42
|
import { registerCallFlowTools } from "./tools/call-flows.js";
|
|
43
43
|
import { registerProjectBlueTools } from "./tools/project-blue.js";
|
|
44
|
+
import { registerReportTools } from "./tools/reports.js";
|
|
44
45
|
const apiUrl = process.env.CONDUYT_API_URL;
|
|
45
46
|
const apiKey = process.env.CONDUYT_API_KEY;
|
|
46
47
|
if (!apiUrl || !apiKey) {
|
|
@@ -104,5 +105,6 @@ registerLifecycleTools(server, client);
|
|
|
104
105
|
registerReplyCaptureTools(server, client);
|
|
105
106
|
registerCallFlowTools(server, client);
|
|
106
107
|
registerProjectBlueTools(server, client);
|
|
108
|
+
registerReportTools(server, client);
|
|
107
109
|
const transport = new StdioServerTransport();
|
|
108
110
|
await server.connect(transport);
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { formatResult } from "../client.js";
|
|
3
|
+
/**
|
|
4
|
+
* Custom reports (reporting P1, 2026-09-10): the Lead Activity grid. A report is a saved definition — a base
|
|
5
|
+
* (contacts, deals, activities, tasks, messages, invoices), columns, filters, a sort, an optional metric and
|
|
6
|
+
* grouping. On the contacts and deals bases the columns can be per-row ROLLUPS (calls, connected calls, talk time,
|
|
7
|
+
* first/last call, SMS and email counts, time to first touch, activities, deals and their value, appointments, drip
|
|
8
|
+
* status, days since created or contacted; on deals: contact name/phone/email, age, time in stage, days to close),
|
|
9
|
+
* the account's CUSTOM FIELDS (`cf:<key>`), a Smart View as the POPULATION, and a second grouping dimension.
|
|
10
|
+
* Reads need the reports scope; creating needs reports create; exporting needs reports export.
|
|
11
|
+
*/
|
|
12
|
+
const filterSchema = z.object({
|
|
13
|
+
field: z.string().describe("A field name from conduyt_report_fields (base column, rollup, or cf:<key>)"),
|
|
14
|
+
operator: z.string().describe("eq, neq, contains, gt, gte, lt, lte, between, in, isNull, isNotNull, or a relative-date operator (within_last_n, today, since_monday, this_calendar_month, previous_month, in_past, in_future…)"),
|
|
15
|
+
value: z.unknown().optional().describe("The value; [from, to] for between; a list for in; {n, unit} for within_last_n / within_next_n"),
|
|
16
|
+
});
|
|
17
|
+
export function registerReportTools(server, client) {
|
|
18
|
+
server.tool("conduyt_report_fields", "The field catalogue a custom report may use on a base: the entity's own columns, its per-row rollups (contacts/deals) and the account's custom fields, with type, operators and whether each can group, sort or be measured. Read this before building a report.", { entity: z.enum(["contacts", "deals", "activities", "tasks", "messages", "invoices"]).describe("The report base") }, async ({ entity }) => formatResult(await client.get(`/api/v1/reports/custom/fields?entity=${encodeURIComponent(entity)}`)));
|
|
19
|
+
server.tool("conduyt_list_reports", "List the account's saved custom reports (shared ones and your own), with their definition and last-run status.", {}, async () => formatResult(await client.get("/api/v1/reports/custom")));
|
|
20
|
+
server.tool("conduyt_create_report", "Create a saved custom report. contacts/deals bases support rollup columns, cf:<key> custom fields, a Smart View population and groupBy2 (see conduyt_report_fields).", {
|
|
21
|
+
name: z.string().min(1).max(120),
|
|
22
|
+
description: z.string().max(500).optional(),
|
|
23
|
+
entity: z.enum(["contacts", "deals", "activities", "tasks", "messages", "invoices"]),
|
|
24
|
+
columns: z.array(z.string()).min(1).max(60).describe("Field names in display order"),
|
|
25
|
+
filters: z.array(filterSchema).max(30).optional(),
|
|
26
|
+
sortBy: z.string().optional(),
|
|
27
|
+
sortDir: z.enum(["asc", "desc"]).optional(),
|
|
28
|
+
groupBy: z.string().optional().describe("A groupable field (chart dimension)"),
|
|
29
|
+
groupBy2: z.string().optional().describe("contacts/deals only: a second grouping dimension (rows = groupBy × groupBy2)"),
|
|
30
|
+
timeGrain: z.enum(["day", "week", "month"]).optional().describe("When groupBy is a date"),
|
|
31
|
+
aggregate: z.enum(["count", "sum", "avg", "min", "max"]).optional(),
|
|
32
|
+
measureField: z.string().optional().describe("A numeric field for sum/avg/min/max (a rollup or cf:<key> works)"),
|
|
33
|
+
chartType: z.enum(["bar", "line", "pie", "table", "funnel", "number"]).optional(),
|
|
34
|
+
population: z.object({ smartViewId: z.string().uuid().nullable().optional() }).optional().describe("contacts/deals only: { smartViewId } runs the report over the contacts in that Smart View"),
|
|
35
|
+
isShared: z.boolean().optional().describe("Visible to the whole account (default false = only you and admins)"),
|
|
36
|
+
}, async ({ name, description, entity, columns, filters, sortBy, sortDir, groupBy, groupBy2, timeGrain, aggregate, measureField, chartType, population, isShared }) => {
|
|
37
|
+
// Inline body (undefined fields drop out in JSON) — readable by the contract verifier's static parser.
|
|
38
|
+
const result = await client.post("/api/v1/reports/custom", {
|
|
39
|
+
name,
|
|
40
|
+
description,
|
|
41
|
+
entity,
|
|
42
|
+
columns,
|
|
43
|
+
filters,
|
|
44
|
+
sortBy,
|
|
45
|
+
sortDir,
|
|
46
|
+
groupBy,
|
|
47
|
+
groupBy2,
|
|
48
|
+
timeGrain,
|
|
49
|
+
aggregate,
|
|
50
|
+
measureField,
|
|
51
|
+
chartType,
|
|
52
|
+
population,
|
|
53
|
+
isShared,
|
|
54
|
+
});
|
|
55
|
+
return formatResult(result);
|
|
56
|
+
});
|
|
57
|
+
server.tool("conduyt_run_report", "Run a saved custom report: a page of rows (per_page ≤ 500), the total, the metric, the chart data (groupBy) and, on contacts/deals with groupBy2, the two-dimensional grouped rows.", {
|
|
58
|
+
id: z.string().uuid().describe("Saved report id (from conduyt_list_reports)"),
|
|
59
|
+
page: z.number().int().min(1).optional(),
|
|
60
|
+
per_page: z.number().int().min(1).max(500).optional(),
|
|
61
|
+
}, async ({ id, page, per_page }) => {
|
|
62
|
+
const params = new URLSearchParams();
|
|
63
|
+
if (page)
|
|
64
|
+
params.set("page", String(page));
|
|
65
|
+
if (per_page)
|
|
66
|
+
params.set("per_page", String(per_page));
|
|
67
|
+
const qs = params.toString();
|
|
68
|
+
return formatResult(await client.post(`/api/v1/reports/custom/${encodeURIComponent(id)}/run${qs ? `?${qs}` : ""}`, {}));
|
|
69
|
+
});
|
|
70
|
+
server.tool("conduyt_preview_report", "Run an UNSAVED report definition (10 rows) to check columns and filters before saving. Same fields as conduyt_create_report.", {
|
|
71
|
+
entity: z.enum(["contacts", "deals", "activities", "tasks", "messages", "invoices"]),
|
|
72
|
+
columns: z.array(z.string()).min(1).max(60),
|
|
73
|
+
filters: z.array(filterSchema).max(30).optional(),
|
|
74
|
+
sortBy: z.string().optional(),
|
|
75
|
+
sortDir: z.enum(["asc", "desc"]).optional(),
|
|
76
|
+
groupBy: z.string().optional(),
|
|
77
|
+
groupBy2: z.string().optional(),
|
|
78
|
+
timeGrain: z.enum(["day", "week", "month"]).optional(),
|
|
79
|
+
aggregate: z.enum(["count", "sum", "avg", "min", "max"]).optional(),
|
|
80
|
+
measureField: z.string().optional(),
|
|
81
|
+
population: z.object({ smartViewId: z.string().uuid().nullable().optional() }).optional(),
|
|
82
|
+
}, async ({ entity, columns, filters, sortBy, sortDir, groupBy, groupBy2, timeGrain, aggregate, measureField, population }) => {
|
|
83
|
+
const result = await client.post("/api/v1/reports/custom/preview", {
|
|
84
|
+
entity,
|
|
85
|
+
columns,
|
|
86
|
+
filters,
|
|
87
|
+
sortBy,
|
|
88
|
+
sortDir,
|
|
89
|
+
groupBy,
|
|
90
|
+
groupBy2,
|
|
91
|
+
timeGrain,
|
|
92
|
+
aggregate,
|
|
93
|
+
measureField,
|
|
94
|
+
population,
|
|
95
|
+
});
|
|
96
|
+
return formatResult(result);
|
|
97
|
+
});
|
|
98
|
+
server.tool("conduyt_export_report", "Export every matching row of a saved report (up to 50,000) as CSV or XLSX text. Returns the file body; for a large report narrow the filters or ask for the scheduled delivery.", {
|
|
99
|
+
id: z.string().uuid(),
|
|
100
|
+
format: z.enum(["csv", "xlsx"]).optional().describe("csv (default) or xlsx"),
|
|
101
|
+
}, async ({ id, format }) => {
|
|
102
|
+
const result = await client.postText(`/api/v1/reports/custom/${encodeURIComponent(id)}/export?format=${format ?? "csv"}`, {});
|
|
103
|
+
return formatResult(result);
|
|
104
|
+
});
|
|
105
|
+
}
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
|
-
"generatedAt": "2026-09-
|
|
3
|
-
"toolCount":
|
|
4
|
-
"totalEndpoints":
|
|
2
|
+
"generatedAt": "2026-09-10T13:43:27.157Z",
|
|
3
|
+
"toolCount": 225,
|
|
4
|
+
"totalEndpoints": 931,
|
|
5
5
|
"counts": {
|
|
6
|
-
"covered":
|
|
6
|
+
"covered": 207,
|
|
7
7
|
"excluded": 283,
|
|
8
|
-
"planned":
|
|
8
|
+
"planned": 441,
|
|
9
9
|
"uncategorized": 0
|
|
10
10
|
},
|
|
11
11
|
"matrix": {
|
|
@@ -3170,12 +3170,16 @@
|
|
|
3170
3170
|
"reason": "additional report surfaces beyond ai/insights"
|
|
3171
3171
|
},
|
|
3172
3172
|
"GET /api/v1/reports/custom": {
|
|
3173
|
-
"status": "
|
|
3174
|
-
"
|
|
3173
|
+
"status": "covered",
|
|
3174
|
+
"tools": [
|
|
3175
|
+
"conduyt_list_reports"
|
|
3176
|
+
]
|
|
3175
3177
|
},
|
|
3176
3178
|
"POST /api/v1/reports/custom": {
|
|
3177
|
-
"status": "
|
|
3178
|
-
"
|
|
3179
|
+
"status": "covered",
|
|
3180
|
+
"tools": [
|
|
3181
|
+
"conduyt_create_report"
|
|
3182
|
+
]
|
|
3179
3183
|
},
|
|
3180
3184
|
"GET /api/v1/reports/custom/:id": {
|
|
3181
3185
|
"status": "planned",
|
|
@@ -3190,16 +3194,26 @@
|
|
|
3190
3194
|
"reason": "additional report surfaces beyond ai/insights"
|
|
3191
3195
|
},
|
|
3192
3196
|
"POST /api/v1/reports/custom/:id/export": {
|
|
3193
|
-
"status": "
|
|
3194
|
-
"
|
|
3197
|
+
"status": "covered",
|
|
3198
|
+
"tools": [
|
|
3199
|
+
"conduyt_export_report"
|
|
3200
|
+
]
|
|
3195
3201
|
},
|
|
3196
3202
|
"POST /api/v1/reports/custom/:id/run": {
|
|
3197
3203
|
"status": "planned",
|
|
3198
3204
|
"reason": "additional report surfaces beyond ai/insights"
|
|
3199
3205
|
},
|
|
3206
|
+
"GET /api/v1/reports/custom/fields": {
|
|
3207
|
+
"status": "covered",
|
|
3208
|
+
"tools": [
|
|
3209
|
+
"conduyt_report_fields"
|
|
3210
|
+
]
|
|
3211
|
+
},
|
|
3200
3212
|
"POST /api/v1/reports/custom/preview": {
|
|
3201
|
-
"status": "
|
|
3202
|
-
"
|
|
3213
|
+
"status": "covered",
|
|
3214
|
+
"tools": [
|
|
3215
|
+
"conduyt_preview_report"
|
|
3216
|
+
]
|
|
3203
3217
|
},
|
|
3204
3218
|
"GET /api/v1/reports/dialer/agent-hourly": {
|
|
3205
3219
|
"status": "planned",
|