@kynver-app/mcp-estimator 0.2.5 → 0.2.7

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kynver-app/mcp-estimator",
3
- "version": "0.2.5",
3
+ "version": "0.2.7",
4
4
  "description": "Kynver Estimator MCP server — chat, estimate, and catalog tools",
5
5
  "type": "module",
6
6
  "bin": {
package/src/server.ts CHANGED
@@ -18,6 +18,7 @@ import * as clientTools from "./tools/client-tools.js";
18
18
  import * as takeoffTools from "./tools/takeoff-tools.js";
19
19
  import * as intakeTools from "./tools/intake-tools.js";
20
20
  import * as remodelEstimateTools from "./tools/remodel-estimate-tools.js";
21
+ import * as remodelDeliverableTools from "./tools/remodel-deliverable-tools.js";
21
22
  import { readOwnPackageVersion } from "./lib/package-version.js";
22
23
 
23
24
  const PACKAGE_VERSION = readOwnPackageVersion(import.meta.url);
@@ -73,6 +74,7 @@ export function createEstimatorServer(): McpServer {
73
74
  register(estimateTools.deleteEstimate.name, { description: estimateTools.deleteEstimate.description, inputSchema: estimateTools.deleteEstimate.inputSchemaZod }, (args) => estimateTools.deleteEstimate.execute(args as any));
74
75
  register(estimateTools.duplicateEstimate.name, { description: estimateTools.duplicateEstimate.description, inputSchema: estimateTools.duplicateEstimate.inputSchemaZod }, (args) => estimateTools.duplicateEstimate.execute(args as any));
75
76
  register(remodelEstimateTools.buildRemodelEstimate.name, { description: remodelEstimateTools.buildRemodelEstimate.description, inputSchema: remodelEstimateTools.buildRemodelEstimate.inputSchemaZod }, (args) => remodelEstimateTools.buildRemodelEstimate.execute(args as any));
77
+ register(remodelDeliverableTools.buildRemodelDeliverable.name, { description: remodelDeliverableTools.buildRemodelDeliverable.description, inputSchema: remodelDeliverableTools.buildRemodelDeliverable.inputSchemaZod }, (args) => remodelDeliverableTools.buildRemodelDeliverable.execute(args as any));
76
78
 
77
79
  // --- Template tools (4) ---
78
80
  register(templateTools.saveTemplate.name, { description: templateTools.saveTemplate.description, inputSchema: templateTools.saveTemplate.inputSchemaZod }, (args) => templateTools.saveTemplate.execute(args as any));
@@ -0,0 +1,72 @@
1
+ import { z } from "zod";
2
+ import * as client from "../lib/kynver-client.js";
3
+
4
+ const packageSchema = z.object({
5
+ intake: z.object({
6
+ projectName: z.string().optional(),
7
+ scopes: z.array(
8
+ z.object({
9
+ key: z.string(),
10
+ label: z.string().optional(),
11
+ quantity: z.number().optional(),
12
+ unit: z.string().optional(),
13
+ serviceCode: z.string().optional(),
14
+ budgetLump: z.number().optional(),
15
+ notes: z.string().optional(),
16
+ })
17
+ ),
18
+ expandScopeComponents: z.boolean().optional(),
19
+ includeStandardAlternates: z.boolean().optional(),
20
+ exclusions: z.array(z.string()).optional(),
21
+ assumptions: z.array(z.string()).optional(),
22
+ notes: z.string().optional(),
23
+ }),
24
+ pricing: z
25
+ .object({
26
+ contingencyPercent: z.number().optional(),
27
+ markupPercent: z.number().optional(),
28
+ profitPercent: z.number().optional(),
29
+ })
30
+ .optional(),
31
+ });
32
+
33
+ const buildDeliverableSchema = z.object({
34
+ preset: z.enum(["matthew-portland-2026-06"]).optional(),
35
+ client: z.object({
36
+ projectTitle: z.string(),
37
+ clientName: z.string().optional(),
38
+ preparedBy: z.string().optional(),
39
+ location: z.string().optional(),
40
+ documentType: z.string().optional(),
41
+ validityNote: z.string().optional(),
42
+ }),
43
+ budgetPackage: packageSchema.optional(),
44
+ fullPackage: packageSchema.optional(),
45
+ alternates: z
46
+ .array(
47
+ z.object({
48
+ key: z.string(),
49
+ label: z.string(),
50
+ description: z.string(),
51
+ budgetPlaceholder: z.number().nullable(),
52
+ })
53
+ )
54
+ .optional(),
55
+ correctionNote: z.string().optional(),
56
+ scopeBasis: z.array(z.string()).optional(),
57
+ });
58
+
59
+ export const buildRemodelDeliverable = {
60
+ name: "estimator_build_remodel_deliverable",
61
+ description:
62
+ "Build a dogfoodable residential remodel deliverable package with distinct budget/base and full/dream scope sections, separate alternates (never in headline totals), client-facing line-item descriptions, HTML/PDF handoff metadata, and MCP tool guidance for deeper detail. Use preset matthew-portland-2026-06 for the Matthew Portland fixture ($339,025 full / $167,200 bank-budget). Does not persist — use handoff JSON + reviewMarkdown to render client PDF/HTML. Supersedes hand-built deliverables that omitted structured sections. For single-scope preview only, use estimator_build_remodel_estimate.",
63
+ inputSchemaZod: buildDeliverableSchema,
64
+ execute: async (args: z.infer<typeof buildDeliverableSchema>): Promise<string> => {
65
+ if (!client.hasApiKey()) return client.noApiKeyMessage();
66
+ const data = await client.post(
67
+ "/estimator/estimates/build-remodel-deliverable",
68
+ args
69
+ );
70
+ return JSON.stringify(data);
71
+ },
72
+ };
@@ -27,7 +27,9 @@ const buildRemodelSchema = z.object({
27
27
  )
28
28
  .optional(),
29
29
  includeStandardAlternates: z.boolean().optional(),
30
+ expandScopeComponents: z.boolean().optional(),
30
31
  exclusions: z.array(z.string()).optional(),
32
+ assumptions: z.array(z.string()).optional(),
31
33
  notes: z.string().optional(),
32
34
  }),
33
35
  takeoffRows: z
@@ -68,7 +70,7 @@ const buildRemodelSchema = z.object({
68
70
  export const buildRemodelEstimate = {
69
71
  name: "estimator_build_remodel_estimate",
70
72
  description:
71
- "Build a reviewable residential remodel estimate from normalized intake scopes, optional takeoff quantities, catalog prices, and overrides. Returns line items with provenance, alternates (both baths, upstairs expansion, roof, wall moving), exclusions, contingency/markup/profit breakdown, and reviewMarkdown. Does not persist — use estimator_generate_estimate_from_takeoff or estimator_create_repair after review. Scope keys: kitchen, bath_full, bath_half, bath_primary, bath_secondary, cabinets, drywall, paint, framing, roof, flooring, electrical_kitchen, electrical_bath.",
73
+ "Build a reviewable residential remodel estimate from normalized intake scopes, optional takeoff quantities, catalog prices, and overrides. Lump room scopes (kitchen, baths) auto-expand into a per-trade breakdown of line items (demolition, cabinetry, countertops, plumbing, electrical, appliances, flooring, tile, finishes) — each with its own scope-of-work description carried in notes — so client-facing output is itemized, not a single vague lump (set intake.expandScopeComponents=false for the legacy single-line behavior). Returns line items with provenance, alternates (both baths, upstairs expansion, roof, wall moving), a default+custom assumptions list, default+custom exclusions, contingency/markup/profit breakdown, and reviewMarkdown. Pass project-specific items via intake.assumptions and intake.exclusions. Does not persist — use estimator_generate_estimate_from_takeoff or estimator_create_repair after review. Room scope keys: kitchen, bath_full, bath_half, bath_primary, bath_secondary. Trade/quantity scope keys: cabinets, drywall, paint, framing, roof, flooring, electrical_kitchen, electrical_bath. Whole-project phase scope keys: general_conditions, permits, demolition, protection, final_clean.",
72
74
  inputSchemaZod: buildRemodelSchema,
73
75
  execute: async (args: z.infer<typeof buildRemodelSchema>): Promise<string> => {
74
76
  if (!client.hasApiKey()) return client.noApiKeyMessage();