@kynver-app/mcp-estimator 0.1.1

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.
Files changed (52) hide show
  1. package/dist/index.d.ts +7 -0
  2. package/dist/index.js +11 -0
  3. package/dist/lib/kynver-client.d.ts +20 -0
  4. package/dist/lib/kynver-client.js +110 -0
  5. package/dist/lib/mcp-sse-server.d.ts +29 -0
  6. package/dist/lib/mcp-sse-server.js +191 -0
  7. package/dist/server.d.ts +6 -0
  8. package/dist/server.js +78 -0
  9. package/dist/sse.d.ts +1 -0
  10. package/dist/sse.js +9 -0
  11. package/dist/tools/catalog-tools.d.ts +387 -0
  12. package/dist/tools/catalog-tools.js +193 -0
  13. package/dist/tools/client-tools.d.ts +193 -0
  14. package/dist/tools/client-tools.js +105 -0
  15. package/dist/tools/company-tools.d.ts +163 -0
  16. package/dist/tools/company-tools.js +98 -0
  17. package/dist/tools/create-estimate.d.ts +107 -0
  18. package/dist/tools/create-estimate.js +64 -0
  19. package/dist/tools/estimate-tools.d.ts +531 -0
  20. package/dist/tools/estimate-tools.js +259 -0
  21. package/dist/tools/estimator-chat.d.ts +25 -0
  22. package/dist/tools/estimator-chat.js +15 -0
  23. package/dist/tools/get-estimate.d.ts +19 -0
  24. package/dist/tools/get-estimate.js +14 -0
  25. package/dist/tools/list-catalog.d.ts +25 -0
  26. package/dist/tools/list-catalog.js +22 -0
  27. package/dist/tools/photo-tools.d.ts +77 -0
  28. package/dist/tools/photo-tools.js +51 -0
  29. package/dist/tools/stats-pdf-tools.d.ts +113 -0
  30. package/dist/tools/stats-pdf-tools.js +73 -0
  31. package/dist/tools/template-tools.d.ts +96 -0
  32. package/dist/tools/template-tools.js +70 -0
  33. package/dist/tools/version-tools.d.ts +46 -0
  34. package/dist/tools/version-tools.js +33 -0
  35. package/dist/tools/vision-tools.d.ts +52 -0
  36. package/dist/tools/vision-tools.js +42 -0
  37. package/package.json +27 -0
  38. package/src/index.ts +13 -0
  39. package/src/lib/kynver-client.ts +136 -0
  40. package/src/lib/mcp-sse-server.ts +249 -0
  41. package/src/server.ts +101 -0
  42. package/src/sse.ts +10 -0
  43. package/src/tools/catalog-tools.ts +217 -0
  44. package/src/tools/client-tools.ts +114 -0
  45. package/src/tools/company-tools.ts +108 -0
  46. package/src/tools/estimate-tools.ts +281 -0
  47. package/src/tools/photo-tools.ts +60 -0
  48. package/src/tools/stats-pdf-tools.ts +80 -0
  49. package/src/tools/template-tools.ts +80 -0
  50. package/src/tools/version-tools.ts +39 -0
  51. package/src/tools/vision-tools.ts +48 -0
  52. package/tsconfig.json +15 -0
@@ -0,0 +1,387 @@
1
+ import { z } from "zod";
2
+ declare const importCatalogSchema: z.ZodObject<{
3
+ message: z.ZodString;
4
+ }, "strip", z.ZodTypeAny, {
5
+ message: string;
6
+ }, {
7
+ message: string;
8
+ }>;
9
+ export declare const importCatalog: {
10
+ name: string;
11
+ description: string;
12
+ inputSchemaZod: z.ZodObject<{
13
+ message: z.ZodString;
14
+ }, "strip", z.ZodTypeAny, {
15
+ message: string;
16
+ }, {
17
+ message: string;
18
+ }>;
19
+ execute: (args: z.infer<typeof importCatalogSchema>) => Promise<string>;
20
+ };
21
+ declare const reviewImportSchema: z.ZodObject<{
22
+ importId: z.ZodString;
23
+ approved: z.ZodOptional<z.ZodBoolean>;
24
+ changes: z.ZodOptional<z.ZodArray<z.ZodObject<{
25
+ index: z.ZodNumber;
26
+ action: z.ZodEnum<["keep", "skip", "edit"]>;
27
+ edits: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
28
+ }, "strip", z.ZodTypeAny, {
29
+ index: number;
30
+ action: "keep" | "skip" | "edit";
31
+ edits?: Record<string, unknown> | undefined;
32
+ }, {
33
+ index: number;
34
+ action: "keep" | "skip" | "edit";
35
+ edits?: Record<string, unknown> | undefined;
36
+ }>, "many">>;
37
+ }, "strip", z.ZodTypeAny, {
38
+ importId: string;
39
+ approved?: boolean | undefined;
40
+ changes?: {
41
+ index: number;
42
+ action: "keep" | "skip" | "edit";
43
+ edits?: Record<string, unknown> | undefined;
44
+ }[] | undefined;
45
+ }, {
46
+ importId: string;
47
+ approved?: boolean | undefined;
48
+ changes?: {
49
+ index: number;
50
+ action: "keep" | "skip" | "edit";
51
+ edits?: Record<string, unknown> | undefined;
52
+ }[] | undefined;
53
+ }>;
54
+ export declare const reviewImport: {
55
+ name: string;
56
+ description: string;
57
+ inputSchemaZod: z.ZodObject<{
58
+ importId: z.ZodString;
59
+ approved: z.ZodOptional<z.ZodBoolean>;
60
+ changes: z.ZodOptional<z.ZodArray<z.ZodObject<{
61
+ index: z.ZodNumber;
62
+ action: z.ZodEnum<["keep", "skip", "edit"]>;
63
+ edits: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
64
+ }, "strip", z.ZodTypeAny, {
65
+ index: number;
66
+ action: "keep" | "skip" | "edit";
67
+ edits?: Record<string, unknown> | undefined;
68
+ }, {
69
+ index: number;
70
+ action: "keep" | "skip" | "edit";
71
+ edits?: Record<string, unknown> | undefined;
72
+ }>, "many">>;
73
+ }, "strip", z.ZodTypeAny, {
74
+ importId: string;
75
+ approved?: boolean | undefined;
76
+ changes?: {
77
+ index: number;
78
+ action: "keep" | "skip" | "edit";
79
+ edits?: Record<string, unknown> | undefined;
80
+ }[] | undefined;
81
+ }, {
82
+ importId: string;
83
+ approved?: boolean | undefined;
84
+ changes?: {
85
+ index: number;
86
+ action: "keep" | "skip" | "edit";
87
+ edits?: Record<string, unknown> | undefined;
88
+ }[] | undefined;
89
+ }>;
90
+ execute: (args: z.infer<typeof reviewImportSchema>) => Promise<string>;
91
+ };
92
+ declare const commitImportSchema: z.ZodObject<{
93
+ importId: z.ZodString;
94
+ }, "strip", z.ZodTypeAny, {
95
+ importId: string;
96
+ }, {
97
+ importId: string;
98
+ }>;
99
+ export declare const commitImport: {
100
+ name: string;
101
+ description: string;
102
+ inputSchemaZod: z.ZodObject<{
103
+ importId: z.ZodString;
104
+ }, "strip", z.ZodTypeAny, {
105
+ importId: string;
106
+ }, {
107
+ importId: string;
108
+ }>;
109
+ execute: (args: z.infer<typeof commitImportSchema>) => Promise<string>;
110
+ };
111
+ declare const setupPriceSchema: z.ZodObject<{
112
+ name: z.ZodString;
113
+ serviceCode: z.ZodString;
114
+ category: z.ZodString;
115
+ materialType: z.ZodOptional<z.ZodNullable<z.ZodString>>;
116
+ unit: z.ZodString;
117
+ materialCost: z.ZodNumber;
118
+ laborCost: z.ZodNumber;
119
+ minCharge: z.ZodOptional<z.ZodNumber>;
120
+ notes: z.ZodOptional<z.ZodString>;
121
+ }, "strip", z.ZodTypeAny, {
122
+ name: string;
123
+ serviceCode: string;
124
+ category: string;
125
+ unit: string;
126
+ materialCost: number;
127
+ laborCost: number;
128
+ materialType?: string | null | undefined;
129
+ minCharge?: number | undefined;
130
+ notes?: string | undefined;
131
+ }, {
132
+ name: string;
133
+ serviceCode: string;
134
+ category: string;
135
+ unit: string;
136
+ materialCost: number;
137
+ laborCost: number;
138
+ materialType?: string | null | undefined;
139
+ minCharge?: number | undefined;
140
+ notes?: string | undefined;
141
+ }>;
142
+ export declare const setupPrice: {
143
+ name: string;
144
+ description: string;
145
+ inputSchemaZod: z.ZodObject<{
146
+ name: z.ZodString;
147
+ serviceCode: z.ZodString;
148
+ category: z.ZodString;
149
+ materialType: z.ZodOptional<z.ZodNullable<z.ZodString>>;
150
+ unit: z.ZodString;
151
+ materialCost: z.ZodNumber;
152
+ laborCost: z.ZodNumber;
153
+ minCharge: z.ZodOptional<z.ZodNumber>;
154
+ notes: z.ZodOptional<z.ZodString>;
155
+ }, "strip", z.ZodTypeAny, {
156
+ name: string;
157
+ serviceCode: string;
158
+ category: string;
159
+ unit: string;
160
+ materialCost: number;
161
+ laborCost: number;
162
+ materialType?: string | null | undefined;
163
+ minCharge?: number | undefined;
164
+ notes?: string | undefined;
165
+ }, {
166
+ name: string;
167
+ serviceCode: string;
168
+ category: string;
169
+ unit: string;
170
+ materialCost: number;
171
+ laborCost: number;
172
+ materialType?: string | null | undefined;
173
+ minCharge?: number | undefined;
174
+ notes?: string | undefined;
175
+ }>;
176
+ execute: (args: z.infer<typeof setupPriceSchema>) => Promise<string>;
177
+ };
178
+ declare const updatePriceSchema: z.ZodObject<{
179
+ itemId: z.ZodString;
180
+ name: z.ZodOptional<z.ZodString>;
181
+ serviceCode: z.ZodOptional<z.ZodString>;
182
+ category: z.ZodOptional<z.ZodString>;
183
+ materialType: z.ZodOptional<z.ZodNullable<z.ZodString>>;
184
+ unit: z.ZodOptional<z.ZodString>;
185
+ materialCost: z.ZodOptional<z.ZodNumber>;
186
+ laborCost: z.ZodOptional<z.ZodNumber>;
187
+ minCharge: z.ZodOptional<z.ZodNumber>;
188
+ notes: z.ZodOptional<z.ZodString>;
189
+ }, "strip", z.ZodTypeAny, {
190
+ itemId: string;
191
+ name?: string | undefined;
192
+ serviceCode?: string | undefined;
193
+ category?: string | undefined;
194
+ materialType?: string | null | undefined;
195
+ unit?: string | undefined;
196
+ materialCost?: number | undefined;
197
+ laborCost?: number | undefined;
198
+ minCharge?: number | undefined;
199
+ notes?: string | undefined;
200
+ }, {
201
+ itemId: string;
202
+ name?: string | undefined;
203
+ serviceCode?: string | undefined;
204
+ category?: string | undefined;
205
+ materialType?: string | null | undefined;
206
+ unit?: string | undefined;
207
+ materialCost?: number | undefined;
208
+ laborCost?: number | undefined;
209
+ minCharge?: number | undefined;
210
+ notes?: string | undefined;
211
+ }>;
212
+ export declare const updatePrice: {
213
+ name: string;
214
+ description: string;
215
+ inputSchemaZod: z.ZodObject<{
216
+ itemId: z.ZodString;
217
+ name: z.ZodOptional<z.ZodString>;
218
+ serviceCode: z.ZodOptional<z.ZodString>;
219
+ category: z.ZodOptional<z.ZodString>;
220
+ materialType: z.ZodOptional<z.ZodNullable<z.ZodString>>;
221
+ unit: z.ZodOptional<z.ZodString>;
222
+ materialCost: z.ZodOptional<z.ZodNumber>;
223
+ laborCost: z.ZodOptional<z.ZodNumber>;
224
+ minCharge: z.ZodOptional<z.ZodNumber>;
225
+ notes: z.ZodOptional<z.ZodString>;
226
+ }, "strip", z.ZodTypeAny, {
227
+ itemId: string;
228
+ name?: string | undefined;
229
+ serviceCode?: string | undefined;
230
+ category?: string | undefined;
231
+ materialType?: string | null | undefined;
232
+ unit?: string | undefined;
233
+ materialCost?: number | undefined;
234
+ laborCost?: number | undefined;
235
+ minCharge?: number | undefined;
236
+ notes?: string | undefined;
237
+ }, {
238
+ itemId: string;
239
+ name?: string | undefined;
240
+ serviceCode?: string | undefined;
241
+ category?: string | undefined;
242
+ materialType?: string | null | undefined;
243
+ unit?: string | undefined;
244
+ materialCost?: number | undefined;
245
+ laborCost?: number | undefined;
246
+ minCharge?: number | undefined;
247
+ notes?: string | undefined;
248
+ }>;
249
+ execute: (args: z.infer<typeof updatePriceSchema>) => Promise<string>;
250
+ };
251
+ declare const getCatalogSchema: z.ZodObject<{
252
+ category: z.ZodOptional<z.ZodString>;
253
+ materialType: z.ZodOptional<z.ZodString>;
254
+ limit: z.ZodOptional<z.ZodNumber>;
255
+ cursor: z.ZodOptional<z.ZodString>;
256
+ }, "strip", z.ZodTypeAny, {
257
+ category?: string | undefined;
258
+ materialType?: string | undefined;
259
+ limit?: number | undefined;
260
+ cursor?: string | undefined;
261
+ }, {
262
+ category?: string | undefined;
263
+ materialType?: string | undefined;
264
+ limit?: number | undefined;
265
+ cursor?: string | undefined;
266
+ }>;
267
+ export declare const getCatalog: {
268
+ name: string;
269
+ description: string;
270
+ inputSchemaZod: z.ZodObject<{
271
+ category: z.ZodOptional<z.ZodString>;
272
+ materialType: z.ZodOptional<z.ZodString>;
273
+ limit: z.ZodOptional<z.ZodNumber>;
274
+ cursor: z.ZodOptional<z.ZodString>;
275
+ }, "strip", z.ZodTypeAny, {
276
+ category?: string | undefined;
277
+ materialType?: string | undefined;
278
+ limit?: number | undefined;
279
+ cursor?: string | undefined;
280
+ }, {
281
+ category?: string | undefined;
282
+ materialType?: string | undefined;
283
+ limit?: number | undefined;
284
+ cursor?: string | undefined;
285
+ }>;
286
+ execute: (args: z.infer<typeof getCatalogSchema>) => Promise<string>;
287
+ };
288
+ declare const getConfigSchema: z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>;
289
+ export declare const getConfig: {
290
+ name: string;
291
+ description: string;
292
+ inputSchemaZod: z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>;
293
+ execute: (_args: z.infer<typeof getConfigSchema>) => Promise<string>;
294
+ };
295
+ declare const updateConfigSchema: z.ZodObject<{
296
+ defaultMarkup: z.ZodOptional<z.ZodNumber>;
297
+ taxRate: z.ZodOptional<z.ZodNumber>;
298
+ companyName: z.ZodOptional<z.ZodString>;
299
+ companyPhone: z.ZodOptional<z.ZodString>;
300
+ companyEmail: z.ZodOptional<z.ZodString>;
301
+ companyAddress: z.ZodOptional<z.ZodString>;
302
+ companyLogo: z.ZodOptional<z.ZodString>;
303
+ licenseNumber: z.ZodOptional<z.ZodString>;
304
+ defaultNotes: z.ZodOptional<z.ZodString>;
305
+ defaultTerms: z.ZodOptional<z.ZodString>;
306
+ }, "strip", z.ZodTypeAny, {
307
+ defaultMarkup?: number | undefined;
308
+ taxRate?: number | undefined;
309
+ companyName?: string | undefined;
310
+ companyPhone?: string | undefined;
311
+ companyEmail?: string | undefined;
312
+ companyAddress?: string | undefined;
313
+ companyLogo?: string | undefined;
314
+ licenseNumber?: string | undefined;
315
+ defaultNotes?: string | undefined;
316
+ defaultTerms?: string | undefined;
317
+ }, {
318
+ defaultMarkup?: number | undefined;
319
+ taxRate?: number | undefined;
320
+ companyName?: string | undefined;
321
+ companyPhone?: string | undefined;
322
+ companyEmail?: string | undefined;
323
+ companyAddress?: string | undefined;
324
+ companyLogo?: string | undefined;
325
+ licenseNumber?: string | undefined;
326
+ defaultNotes?: string | undefined;
327
+ defaultTerms?: string | undefined;
328
+ }>;
329
+ export declare const updateConfig: {
330
+ name: string;
331
+ description: string;
332
+ inputSchemaZod: z.ZodObject<{
333
+ defaultMarkup: z.ZodOptional<z.ZodNumber>;
334
+ taxRate: z.ZodOptional<z.ZodNumber>;
335
+ companyName: z.ZodOptional<z.ZodString>;
336
+ companyPhone: z.ZodOptional<z.ZodString>;
337
+ companyEmail: z.ZodOptional<z.ZodString>;
338
+ companyAddress: z.ZodOptional<z.ZodString>;
339
+ companyLogo: z.ZodOptional<z.ZodString>;
340
+ licenseNumber: z.ZodOptional<z.ZodString>;
341
+ defaultNotes: z.ZodOptional<z.ZodString>;
342
+ defaultTerms: z.ZodOptional<z.ZodString>;
343
+ }, "strip", z.ZodTypeAny, {
344
+ defaultMarkup?: number | undefined;
345
+ taxRate?: number | undefined;
346
+ companyName?: string | undefined;
347
+ companyPhone?: string | undefined;
348
+ companyEmail?: string | undefined;
349
+ companyAddress?: string | undefined;
350
+ companyLogo?: string | undefined;
351
+ licenseNumber?: string | undefined;
352
+ defaultNotes?: string | undefined;
353
+ defaultTerms?: string | undefined;
354
+ }, {
355
+ defaultMarkup?: number | undefined;
356
+ taxRate?: number | undefined;
357
+ companyName?: string | undefined;
358
+ companyPhone?: string | undefined;
359
+ companyEmail?: string | undefined;
360
+ companyAddress?: string | undefined;
361
+ companyLogo?: string | undefined;
362
+ licenseNumber?: string | undefined;
363
+ defaultNotes?: string | undefined;
364
+ defaultTerms?: string | undefined;
365
+ }>;
366
+ execute: (args: z.infer<typeof updateConfigSchema>) => Promise<string>;
367
+ };
368
+ declare const importTemplateSchema: z.ZodObject<{
369
+ templateId: z.ZodOptional<z.ZodString>;
370
+ }, "strip", z.ZodTypeAny, {
371
+ templateId?: string | undefined;
372
+ }, {
373
+ templateId?: string | undefined;
374
+ }>;
375
+ export declare const importTemplate: {
376
+ name: string;
377
+ description: string;
378
+ inputSchemaZod: z.ZodObject<{
379
+ templateId: z.ZodOptional<z.ZodString>;
380
+ }, "strip", z.ZodTypeAny, {
381
+ templateId?: string | undefined;
382
+ }, {
383
+ templateId?: string | undefined;
384
+ }>;
385
+ execute: (args: z.infer<typeof importTemplateSchema>) => Promise<string>;
386
+ };
387
+ export {};
@@ -0,0 +1,193 @@
1
+ import { z } from "zod";
2
+ import * as client from "../lib/kynver-client.js";
3
+ // --- estimator_import_catalog ---
4
+ const importCatalogSchema = z.object({
5
+ message: z.string(),
6
+ });
7
+ export const importCatalog = {
8
+ name: "estimator_import_catalog",
9
+ description: "Start a catalog import from a file. This is a placeholder — MCP cannot do file uploads. Describe the import request in the message field and the system will guide the user through the upload flow.",
10
+ inputSchemaZod: importCatalogSchema,
11
+ execute: async (args) => {
12
+ if (!client.hasApiKey())
13
+ return client.noApiKeyMessage();
14
+ const data = await client.post("/v1/agents/kynver-estimator/chat", {
15
+ message: args.message,
16
+ });
17
+ return JSON.stringify(data);
18
+ },
19
+ };
20
+ // --- estimator_review_import ---
21
+ const reviewImportSchema = z.object({
22
+ importId: z.string(),
23
+ approved: z.boolean().optional(),
24
+ changes: z
25
+ .array(z.object({
26
+ index: z.number(),
27
+ action: z.enum(["keep", "skip", "edit"]),
28
+ edits: z.record(z.unknown()).optional(),
29
+ }))
30
+ .optional(),
31
+ });
32
+ export const reviewImport = {
33
+ name: "estimator_review_import",
34
+ description: "Review a pending catalog import batch before committing. Shows parsed rows with suggested service codes, categories, and pricing. You can approve all, skip individual rows, or edit values before committing. Requires an importId from a previous import.",
35
+ inputSchemaZod: reviewImportSchema,
36
+ execute: async (args) => {
37
+ if (!client.hasApiKey())
38
+ return client.noApiKeyMessage();
39
+ const { importId, ...body } = args;
40
+ const data = await client.patch(`/estimator/import/${importId}`, body);
41
+ return JSON.stringify(data);
42
+ },
43
+ };
44
+ // --- estimator_commit_import ---
45
+ const commitImportSchema = z.object({
46
+ importId: z.string(),
47
+ });
48
+ export const commitImport = {
49
+ name: "estimator_commit_import",
50
+ description: "Finalize a reviewed catalog import, writing all approved rows into the user's service catalog. Requires an importId that has been reviewed. This action cannot be undone — rows are added permanently.",
51
+ inputSchemaZod: commitImportSchema,
52
+ execute: async (args) => {
53
+ if (!client.hasApiKey())
54
+ return client.noApiKeyMessage();
55
+ const data = await client.post(`/estimator/import/${args.importId}/commit`, {});
56
+ return JSON.stringify(data);
57
+ },
58
+ };
59
+ // --- estimator_setup_price ---
60
+ const setupPriceSchema = z.object({
61
+ name: z.string(),
62
+ serviceCode: z.string(),
63
+ category: z.string(),
64
+ materialType: z.string().nullable().optional(),
65
+ unit: z.string(),
66
+ materialCost: z.number().min(0),
67
+ laborCost: z.number().min(0),
68
+ minCharge: z.number().min(0).optional(),
69
+ notes: z.string().optional(),
70
+ });
71
+ export const setupPrice = {
72
+ name: "estimator_setup_price",
73
+ description: "Add a new service to the user's price book (service catalog). Every service needs: a unique serviceCode (e.g., ROOF_INSPECT, SHINGLE_REPAIR), a display name, category (tear_off, decking, underlayment, field_install, flashing, ridge_cap, ventilation, gutters, cleanup, permit, misc, etc.), unit (sq_ft, linear_ft, each, sheet, roll, bundle, hour, lump), and material/labor costs. Items in the catalog are used when creating estimates.",
74
+ inputSchemaZod: setupPriceSchema,
75
+ execute: async (args) => {
76
+ if (!client.hasApiKey())
77
+ return client.noApiKeyMessage();
78
+ const data = await client.post("/estimator/catalog", args);
79
+ return JSON.stringify(data);
80
+ },
81
+ };
82
+ // --- estimator_update_price ---
83
+ const updatePriceSchema = z.object({
84
+ itemId: z.string(),
85
+ name: z.string().optional(),
86
+ serviceCode: z.string().optional(),
87
+ category: z.string().optional(),
88
+ materialType: z.string().nullable().optional(),
89
+ unit: z.string().optional(),
90
+ materialCost: z.number().min(0).optional(),
91
+ laborCost: z.number().min(0).optional(),
92
+ minCharge: z.number().min(0).optional(),
93
+ notes: z.string().optional(),
94
+ });
95
+ export const updatePrice = {
96
+ name: "estimator_update_price",
97
+ description: "Update an existing item in the service catalog. Use estimator_get_catalog first to find the itemId. You can change the name, service code, category, unit, material cost, labor cost, minimum charge, or notes.",
98
+ inputSchemaZod: updatePriceSchema,
99
+ execute: async (args) => {
100
+ if (!client.hasApiKey())
101
+ return client.noApiKeyMessage();
102
+ const { itemId, ...body } = args;
103
+ const data = await client.patch(`/estimator/catalog/${itemId}`, body);
104
+ return JSON.stringify(data);
105
+ },
106
+ };
107
+ // --- estimator_get_catalog ---
108
+ const getCatalogSchema = z.object({
109
+ category: z.string().optional(),
110
+ materialType: z.string().optional(),
111
+ limit: z.number().optional(),
112
+ cursor: z.string().optional(),
113
+ });
114
+ export const getCatalog = {
115
+ name: "estimator_get_catalog",
116
+ description: "List all items in the user's service catalog (price book). Returns service codes, names, categories, units, and material/labor costs. IMPORTANT: Always call this before creating estimates to get valid service codes. Optional filters: category (tear_off, decking, underlayment, field_install, ridge_hip, flashing, misc, …) and materialType (asphalt_architectural, asphalt_3tab, metal_standing_seam, tpo, …) must match those exact enum strings — when unsure, omit both to fetch the full catalog.",
117
+ inputSchemaZod: getCatalogSchema,
118
+ execute: async (args) => {
119
+ if (!client.hasApiKey())
120
+ return client.noApiKeyMessage();
121
+ const params = new URLSearchParams();
122
+ if (args.category)
123
+ params.set("category", args.category);
124
+ if (args.materialType)
125
+ params.set("materialType", args.materialType);
126
+ if (args.limit != null)
127
+ params.set("limit", String(args.limit));
128
+ if (args.cursor)
129
+ params.set("cursor", args.cursor);
130
+ const q = params.toString();
131
+ const path = q ? `/estimator/catalog?${q}` : "/estimator/catalog";
132
+ const data = await client.get(path);
133
+ return JSON.stringify(data);
134
+ },
135
+ };
136
+ // --- estimator_get_config ---
137
+ const getConfigSchema = z.object({});
138
+ export const getConfig = {
139
+ name: "estimator_get_config",
140
+ description: "Get the user's estimator settings — company name, default markup/waste percentage, tax rate, currency, contact info, license number, and default notes/terms for estimates.",
141
+ inputSchemaZod: getConfigSchema,
142
+ execute: async (_args) => {
143
+ if (!client.hasApiKey())
144
+ return client.noApiKeyMessage();
145
+ const data = await client.get("/estimator/config");
146
+ return JSON.stringify(data);
147
+ },
148
+ };
149
+ // --- estimator_update_config ---
150
+ const updateConfigSchema = z.object({
151
+ defaultMarkup: z.number().optional(),
152
+ taxRate: z.number().optional(),
153
+ companyName: z.string().optional(),
154
+ companyPhone: z.string().optional(),
155
+ companyEmail: z.string().optional(),
156
+ companyAddress: z.string().optional(),
157
+ companyLogo: z.string().optional(),
158
+ licenseNumber: z.string().optional(),
159
+ defaultNotes: z.string().optional(),
160
+ defaultTerms: z.string().optional(),
161
+ });
162
+ export const updateConfig = {
163
+ name: "estimator_update_config",
164
+ description: "Update the user's estimator settings. You can set: companyName, defaultMarkup (waste %), taxRate, companyPhone, companyEmail, companyAddress, companyLogo (URL), licenseNumber, defaultNotes (appended to every estimate), and defaultTerms (terms & conditions).",
165
+ inputSchemaZod: updateConfigSchema,
166
+ execute: async (args) => {
167
+ if (!client.hasApiKey())
168
+ return client.noApiKeyMessage();
169
+ const data = await client.patch("/estimator/config", args);
170
+ return JSON.stringify(data);
171
+ },
172
+ };
173
+ // --- estimator_import_template ---
174
+ const importTemplateSchema = z.object({
175
+ templateId: z.string().optional(),
176
+ });
177
+ export const importTemplate = {
178
+ name: "estimator_import_template",
179
+ description: "Import a pre-built pricing catalog template into the user's service catalog. Call without arguments to see available templates (returns id, name, description, item count). Call with a templateId to import all items. These are MATERIAL COSTS ONLY — users should add their own labor rates after import. Items that already exist in the user's catalog are skipped (never overwritten).",
180
+ inputSchemaZod: importTemplateSchema,
181
+ execute: async (args) => {
182
+ if (!client.hasApiKey())
183
+ return client.noApiKeyMessage();
184
+ if (!args.templateId) {
185
+ const data = await client.get("/estimator/catalog/templates");
186
+ return JSON.stringify(data);
187
+ }
188
+ const data = await client.post("/estimator/catalog/templates", {
189
+ templateId: args.templateId,
190
+ });
191
+ return JSON.stringify(data);
192
+ },
193
+ };