@decantr/mcp-server 2.0.0 → 2.1.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/README.md CHANGED
@@ -13,6 +13,7 @@ Design intelligence for AI-generated UI. Make Claude, Cursor, and Windsurf gener
13
13
  ![Decantr MCP demo](https://raw.githubusercontent.com/decantr-ai/decantr/main/packages/mcp-server/assets/decantr-demo.gif)
14
14
 
15
15
  - **Structured design context** -- gives your AI assistant patterns, layouts, and component specs instead of letting it guess
16
+ - **Evidence-backed repair loops** -- gives AI agents Project Health, Evidence Bundles, workspace health, and scoped repair prompts without uploading source
16
17
  - **Drift detection** -- catches when generated code deviates from your design intent
17
18
  - **Zero config** -- run with `npx`, no API keys or accounts required
18
19
 
@@ -138,6 +139,10 @@ The server exposes Decantr registry, context, benchmark, and verification tools.
138
139
  | `decantr_compile_execution_packs` | Compile a hosted execution-pack bundle from a local or inline essence document | `{ "path": "./decantr.essence.json", "namespace": "@official" }` |
139
140
  | `decantr_audit_project` | Run the schema-backed Decantr project audit against essence and compiled packs, with hosted fallback when local pack artifacts are missing | `{ "namespace": "@official" }` |
140
141
  | `decantr_critique` | Critique a file against the compiled review contract, with hosted fallback when local review packs are missing | `{ "file_path": "./src/pages/Overview.tsx", "namespace": "@official" }` |
142
+ | `decantr_get_evidence_bundle` | Generate the local privacy-redacted Evidence Bundle for a project | `{ "project_path": "apps/web" }` |
143
+ | `decantr_workspace_health` | Discover Decantr projects and return aggregate workspace health | `{ "workspace_root": ".", "max_projects": 100 }` |
144
+ | `decantr_get_repair_prompt` | Return the scoped repair prompt for a health finding | `{ "finding_id": "assertion-contract-context-pack-manifest" }` |
145
+ | `decantr_run_health_loop` | Run health, evidence, and next repair prompt in one local agent loop | `{ "project_path": "apps/web" }` |
141
146
  | `decantr_get_showcase_benchmarks` | Read the audited showcase corpus manifest, shortlist, or verification report | `{ "view": "verification" }` |
142
147
 
143
148
  For the broader product surface and support policy, see the root Decantr docs and package support matrix.
@@ -169,8 +174,10 @@ The AI assistant calls these tools behind the scenes:
169
174
  7. `decantr_check_drift` -- validates the generated code against the Essence spec before presenting it
170
175
  8. `decantr_critique` -- critiques a specific file, falling back to the hosted verifier when the local review pack is missing
171
176
  9. `decantr_audit_project` -- runs the stronger project-level audit once the implementation is in place
177
+ 10. `decantr_get_evidence_bundle` -- returns the local evidence bundle for the AI repair loop
178
+ 11. `decantr_get_repair_prompt` -- gives the assistant exact finding evidence, constraints to preserve, and commands to rerun
172
179
 
173
- The AI now generates code with the right layout structure, correct components, and consistent styling -- not a generic guess.
180
+ The AI now generates code with the right layout structure, correct components, and consistent styling, then gets a scoped evidence-backed repair loop instead of a generic guess.
174
181
 
175
182
  ## License
176
183
 
package/dist/bin.js CHANGED
@@ -1,2 +1,2 @@
1
1
  #!/usr/bin/env node
2
- import "./chunk-MUNBODQK.js";
2
+ import "./chunk-FEXPLJKB.js";
@@ -469,6 +469,326 @@ var WRITE_TOOL = {
469
469
  idempotentHint: false,
470
470
  openWorldHint: false
471
471
  };
472
+ var MCP_PROJECT_HEALTH_SCHEMA_URL = "https://decantr.ai/schemas/project-health-report.v1.json";
473
+ var MCP_WORKSPACE_HEALTH_SCHEMA_URL = "https://decantr.ai/schemas/workspace-health-report.v1.json";
474
+ var MCP_WORKSPACE_IGNORES = /* @__PURE__ */ new Set([
475
+ ".git",
476
+ ".next",
477
+ ".turbo",
478
+ ".vercel",
479
+ "coverage",
480
+ "dist",
481
+ "node_modules",
482
+ "playwright-report"
483
+ ]);
484
+ function mcpSlug(value) {
485
+ return value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80);
486
+ }
487
+ function mcpStatusFromCounts(counts) {
488
+ if (counts.errorCount > 0) return "error";
489
+ if (counts.warnCount > 0) return "warning";
490
+ return "healthy";
491
+ }
492
+ function mcpScoreFromCounts(counts) {
493
+ return Math.max(0, Math.min(100, 100 - counts.errorCount * 15 - counts.warnCount * 5 - counts.infoCount));
494
+ }
495
+ function mcpCommandsForFinding(source) {
496
+ switch (source) {
497
+ case "assertion":
498
+ return ["decantr refresh", "decantr health --evidence"];
499
+ case "brownfield":
500
+ return ["decantr analyze", "decantr init --existing --merge-proposal", "decantr health"];
501
+ case "browser":
502
+ return ["decantr health --browser", "decantr health --evidence"];
503
+ case "check":
504
+ return ["decantr check", "decantr health"];
505
+ case "design-token":
506
+ return ["decantr export --to figma-tokens", "decantr health --evidence"];
507
+ case "interaction":
508
+ return ["decantr check --strict", "decantr health"];
509
+ case "pack":
510
+ return ["decantr refresh", "decantr registry get-pack review --write-context", "decantr health"];
511
+ case "runtime":
512
+ return ["npm run build", "decantr health"];
513
+ default:
514
+ return ["decantr audit", "decantr health"];
515
+ }
516
+ }
517
+ function mcpSourceFromFinding(finding) {
518
+ const category = finding.category.toLowerCase();
519
+ const id = finding.id.toLowerCase();
520
+ const rule = finding.rule?.toLowerCase() ?? "";
521
+ if (category.includes("runtime") || category.includes("document") || category.includes("performance")) {
522
+ return "runtime";
523
+ }
524
+ if (category.includes("pack") || category.includes("review contract")) {
525
+ return "pack";
526
+ }
527
+ if (category.includes("interaction") || id.includes("interaction") || rule.includes("interaction")) {
528
+ return "interaction";
529
+ }
530
+ return "audit";
531
+ }
532
+ function mcpBuildRepairPrompt(input) {
533
+ return [
534
+ "You are fixing one Decantr Project Health finding in this local workspace.",
535
+ "",
536
+ "Read `DECANTR.md`, `decantr.essence.json`, and `.decantr/context/scaffold-pack.md` if they exist. For route or page work, read the matching page/section packs before editing.",
537
+ "",
538
+ `Finding: ${input.id}`,
539
+ `Source: ${input.source}`,
540
+ `Severity: ${input.severity}`,
541
+ `Category: ${input.category}`,
542
+ `Message: ${input.message}`,
543
+ input.evidence.length > 0 ? `Evidence:
544
+ ${input.evidence.map((entry) => `- ${entry}`).join("\n")}` : null,
545
+ input.suggestedFix ? `Suggested fix: ${input.suggestedFix}` : null,
546
+ "",
547
+ "Make the smallest coherent code or contract change that resolves this finding. Preserve the existing framework, routing, styling system, and Decantr workflow mode unless the finding explicitly requires a contract update.",
548
+ "Do not rewrite unrelated routes, replace the styling system, remove existing product behavior, or regenerate Decantr artifacts unless the finding is about stale or missing generated context.",
549
+ "",
550
+ `After the fix, run:
551
+ ${input.commands.map((command) => `- ${command}`).join("\n")}`
552
+ ].filter((line) => Boolean(line)).join("\n");
553
+ }
554
+ function mcpHealthFinding(input) {
555
+ const id = `${input.source}-${mcpSlug(input.baseId || input.rule || `${input.category}-${input.message}`)}`;
556
+ const commands = mcpCommandsForFinding(input.source);
557
+ return {
558
+ id,
559
+ source: input.source,
560
+ category: input.category,
561
+ severity: input.severity,
562
+ message: input.message,
563
+ evidence: input.evidence ?? [],
564
+ target: input.target,
565
+ file: input.file,
566
+ rule: input.rule,
567
+ suggestedFix: input.suggestedFix,
568
+ remediation: {
569
+ summary: input.suggestedFix || `Resolve ${input.category.toLowerCase()} finding.`,
570
+ commands,
571
+ prompt: mcpBuildRepairPrompt({
572
+ id,
573
+ source: input.source,
574
+ category: input.category,
575
+ severity: input.severity,
576
+ message: input.message,
577
+ evidence: input.evidence ?? [],
578
+ suggestedFix: input.suggestedFix,
579
+ commands
580
+ })
581
+ }
582
+ };
583
+ }
584
+ function mcpCollectDeclaredRoutes(essence) {
585
+ if (!essence || !isV42(essence)) return [];
586
+ return Object.keys(essence.blueprint.routes ?? {}).sort();
587
+ }
588
+ function mcpReportFromAudit(projectRoot, audit, assertions) {
589
+ const findings = [];
590
+ const seen = /* @__PURE__ */ new Set();
591
+ const pushUnique = (finding) => {
592
+ const key = `${finding.rule ?? finding.id}|${finding.message}`;
593
+ if (seen.has(key)) return;
594
+ seen.add(key);
595
+ findings.push(finding);
596
+ };
597
+ for (const finding of audit.findings) {
598
+ pushUnique(
599
+ mcpHealthFinding({
600
+ source: mcpSourceFromFinding(finding),
601
+ category: finding.category,
602
+ severity: finding.severity,
603
+ message: finding.message,
604
+ evidence: finding.evidence,
605
+ target: finding.target,
606
+ file: finding.file,
607
+ rule: finding.rule,
608
+ suggestedFix: finding.suggestedFix,
609
+ baseId: finding.id
610
+ })
611
+ );
612
+ }
613
+ for (const assertion of assertions) {
614
+ if (assertion.status !== "failed") continue;
615
+ pushUnique(
616
+ mcpHealthFinding({
617
+ source: "assertion",
618
+ category: `Contract ${assertion.category}`,
619
+ severity: assertion.severity,
620
+ message: assertion.message,
621
+ evidence: assertion.evidence,
622
+ target: assertion.target,
623
+ rule: assertion.rule,
624
+ suggestedFix: assertion.suggestedFix,
625
+ baseId: assertion.id
626
+ })
627
+ );
628
+ }
629
+ if (!audit.valid && findings.every((finding) => finding.severity !== "error")) {
630
+ pushUnique(
631
+ mcpHealthFinding({
632
+ source: "audit",
633
+ category: "Project Contract",
634
+ severity: "error",
635
+ message: "Project audit is not valid.",
636
+ evidence: ["The verifier returned valid=false."],
637
+ rule: "project-audit-invalid",
638
+ suggestedFix: "Resolve blocking audit findings and rerun `decantr health`."
639
+ })
640
+ );
641
+ }
642
+ const counts = {
643
+ errorCount: findings.filter((finding) => finding.severity === "error").length,
644
+ warnCount: findings.filter((finding) => finding.severity === "warn").length,
645
+ infoCount: findings.filter((finding) => finding.severity === "info").length
646
+ };
647
+ const manifest = audit.packManifest;
648
+ return {
649
+ $schema: MCP_PROJECT_HEALTH_SCHEMA_URL,
650
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
651
+ projectRoot,
652
+ status: mcpStatusFromCounts(counts),
653
+ score: mcpScoreFromCounts(counts),
654
+ summary: {
655
+ ...counts,
656
+ findingCount: findings.length,
657
+ workflowMode: null,
658
+ adoptionMode: null,
659
+ essenceVersion: audit.summary.essenceVersion,
660
+ pageCount: audit.summary.pageCount,
661
+ runtimeAuditChecked: audit.summary.runtimeAuditChecked,
662
+ runtimePassed: audit.summary.runtimePassed,
663
+ packManifestPresent: audit.summary.packManifestPresent,
664
+ reviewPackPresent: audit.summary.reviewPackPresent
665
+ },
666
+ routes: {
667
+ declared: mcpCollectDeclaredRoutes(audit.essence),
668
+ runtimeChecked: audit.runtimeAudit.routeHintsChecked,
669
+ runtimeMatched: audit.runtimeAudit.routeHintsMatched,
670
+ runtimeCoverageOk: audit.summary.runtimeAuditChecked ? audit.runtimeAudit.routeHintsCoverageOk : null,
671
+ issues: findings.filter(
672
+ (finding) => finding.category.toLowerCase().includes("route") || finding.rule?.toLowerCase().includes("route") || finding.id.toLowerCase().includes("route")
673
+ ).map((finding) => finding.message)
674
+ },
675
+ packs: {
676
+ manifestPresent: Boolean(manifest),
677
+ reviewPackPresent: Boolean(manifest?.review ?? audit.reviewPack),
678
+ scaffoldPackPresent: Boolean(manifest?.scaffold),
679
+ sectionPackCount: manifest?.sections.length ?? 0,
680
+ pagePackCount: manifest?.pages.length ?? 0,
681
+ mutationPackCount: manifest?.mutations?.length ?? 0,
682
+ generatedAt: typeof manifest?.generatedAt === "string" ? manifest.generatedAt : null
683
+ },
684
+ ci: {
685
+ recommendedCommand: "decantr health --ci --fail-on error",
686
+ failOn: "error"
687
+ },
688
+ findings
689
+ };
690
+ }
691
+ function resolveMcpProjectRoot(value) {
692
+ if (value == null) return process.cwd();
693
+ if (typeof value !== "string") {
694
+ throw new Error("project_path must be a string when provided.");
695
+ }
696
+ return resolveWorkspacePath(value);
697
+ }
698
+ async function getMcpHealthState(projectRoot) {
699
+ const { auditProject, createContractAssertions, createEvidenceBundle } = await import("@decantr/verifier");
700
+ const audit = await auditProject(projectRoot);
701
+ const assertions = createContractAssertions(projectRoot, audit);
702
+ const report = mcpReportFromAudit(projectRoot, audit, assertions);
703
+ const evidence = createEvidenceBundle({
704
+ projectRoot,
705
+ audit,
706
+ assertions,
707
+ report,
708
+ workspaceConfigPath: existsSync(join2(projectRoot, ".decantr", "workspace.json")) ? join2(projectRoot, ".decantr", "workspace.json") : null
709
+ });
710
+ return { audit, assertions, report, evidence };
711
+ }
712
+ function discoverMcpWorkspaceProjects(root, maxProjects = 500) {
713
+ const projects = [];
714
+ function walk(dir, depth) {
715
+ if (projects.length >= maxProjects || depth > 6) return;
716
+ if (existsSync(join2(dir, "decantr.essence.json"))) {
717
+ const path = relative2(root, dir).replace(/\\/g, "/") || ".";
718
+ projects.push({
719
+ id: path.replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/^-+|-+$/g, "") || "project",
720
+ path,
721
+ absolutePath: dir
722
+ });
723
+ return;
724
+ }
725
+ for (const entry of readdirSync(dir, { withFileTypes: true })) {
726
+ if (!entry.isDirectory() || entry.name.startsWith(".")) continue;
727
+ if (MCP_WORKSPACE_IGNORES.has(entry.name)) continue;
728
+ walk(join2(dir, entry.name), depth + 1);
729
+ if (projects.length >= maxProjects) return;
730
+ }
731
+ }
732
+ walk(root, 0);
733
+ return projects.sort((a, b) => a.path.localeCompare(b.path));
734
+ }
735
+ async function getMcpWorkspaceHealth(args) {
736
+ const root = args.workspace_root == null ? process.cwd() : resolveMcpProjectRoot(args.workspace_root);
737
+ const maxProjects = typeof args.max_projects === "number" && Number.isFinite(args.max_projects) ? Math.max(1, Math.floor(args.max_projects)) : 500;
738
+ const discovered = discoverMcpWorkspaceProjects(root, maxProjects);
739
+ const projects = [];
740
+ for (const project of discovered) {
741
+ const startedAt = Date.now();
742
+ try {
743
+ const state = await getMcpHealthState(project.absolutePath);
744
+ projects.push({
745
+ id: project.id,
746
+ path: project.path,
747
+ status: state.report.status,
748
+ score: state.report.score,
749
+ errorCount: state.report.summary.errorCount,
750
+ warnCount: state.report.summary.warnCount,
751
+ infoCount: state.report.summary.infoCount,
752
+ findingCount: state.report.summary.findingCount,
753
+ durationMs: Date.now() - startedAt,
754
+ changed: false,
755
+ source: "auto",
756
+ error: null
757
+ });
758
+ } catch (error) {
759
+ projects.push({
760
+ id: project.id,
761
+ path: project.path,
762
+ status: "failed",
763
+ score: 0,
764
+ errorCount: 1,
765
+ warnCount: 0,
766
+ infoCount: 0,
767
+ findingCount: 1,
768
+ durationMs: Date.now() - startedAt,
769
+ changed: false,
770
+ source: "auto",
771
+ error: error.message
772
+ });
773
+ }
774
+ }
775
+ return {
776
+ $schema: MCP_WORKSPACE_HEALTH_SCHEMA_URL,
777
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
778
+ workspaceRoot: "<workspace>",
779
+ changedOnly: false,
780
+ since: null,
781
+ summary: {
782
+ projectCount: discovered.length,
783
+ checkedCount: projects.length,
784
+ healthyCount: projects.filter((project) => project.status === "healthy").length,
785
+ warningCount: projects.filter((project) => project.status === "warning").length,
786
+ errorCount: projects.filter((project) => project.status === "error").length,
787
+ failedCount: projects.filter((project) => project.status === "failed").length
788
+ },
789
+ projects
790
+ };
791
+ }
472
792
  var TOOLS = [
473
793
  // 1. decantr_read_essence — local read
474
794
  {
@@ -940,6 +1260,82 @@ var TOOLS = [
940
1260
  required: ["file_path"]
941
1261
  },
942
1262
  annotations: READ_ONLY_NETWORK
1263
+ },
1264
+ // 22. decantr_get_evidence_bundle — local reliability artifact
1265
+ {
1266
+ name: "decantr_get_evidence_bundle",
1267
+ title: "Get Evidence Bundle",
1268
+ description: "Generate a local Evidence Bundle for the current Decantr project. The bundle redacts source, prompts, secrets, absolute paths, repo names, and screenshots by default.",
1269
+ inputSchema: {
1270
+ type: "object",
1271
+ properties: {
1272
+ project_path: {
1273
+ type: "string",
1274
+ description: "Optional relative project path inside the active workspace. Defaults to the current working directory."
1275
+ }
1276
+ }
1277
+ },
1278
+ annotations: READ_ONLY
1279
+ },
1280
+ // 23. decantr_workspace_health — local workspace reliability scan
1281
+ {
1282
+ name: "decantr_workspace_health",
1283
+ title: "Workspace Health",
1284
+ description: "Discover Decantr projects in the active workspace and return deterministic aggregate health for monorepos with many Decantr apps.",
1285
+ inputSchema: {
1286
+ type: "object",
1287
+ properties: {
1288
+ workspace_root: {
1289
+ type: "string",
1290
+ description: "Optional relative workspace root inside the active workspace. Defaults to the current working directory."
1291
+ },
1292
+ max_projects: {
1293
+ type: "number",
1294
+ description: "Optional cap on discovered projects. Defaults to 500."
1295
+ }
1296
+ }
1297
+ },
1298
+ annotations: READ_ONLY
1299
+ },
1300
+ // 24. decantr_get_repair_prompt — local AI repair loop
1301
+ {
1302
+ name: "decantr_get_repair_prompt",
1303
+ title: "Get Repair Prompt",
1304
+ description: "Return an AI-ready repair prompt for a Project Health finding, including exact finding evidence, preserved constraints, do-not-change guidance, and rerun commands.",
1305
+ inputSchema: {
1306
+ type: "object",
1307
+ properties: {
1308
+ project_path: {
1309
+ type: "string",
1310
+ description: "Optional relative project path inside the active workspace. Defaults to the current working directory."
1311
+ },
1312
+ finding_id: {
1313
+ type: "string",
1314
+ description: "Optional finding id. Defaults to the first error or warning, then the first finding."
1315
+ }
1316
+ }
1317
+ },
1318
+ annotations: READ_ONLY
1319
+ },
1320
+ // 25. decantr_run_health_loop — local evidence + repair loop
1321
+ {
1322
+ name: "decantr_run_health_loop",
1323
+ title: "Run Health Loop",
1324
+ description: "Run Project Health, produce evidence, and return the next repair prompt for AI agents without uploading project source.",
1325
+ inputSchema: {
1326
+ type: "object",
1327
+ properties: {
1328
+ project_path: {
1329
+ type: "string",
1330
+ description: "Optional relative project path inside the active workspace. Defaults to the current working directory."
1331
+ },
1332
+ finding_id: {
1333
+ type: "string",
1334
+ description: "Optional finding id to target. Defaults to the first error or warning, then the first finding."
1335
+ }
1336
+ }
1337
+ },
1338
+ annotations: READ_ONLY
943
1339
  }
944
1340
  ];
945
1341
  async function handleTool(name, args) {
@@ -2102,6 +2498,96 @@ async function handleTool(name, args) {
2102
2498
  }
2103
2499
  return auditProject(projectRoot);
2104
2500
  }
2501
+ case "decantr_get_evidence_bundle": {
2502
+ try {
2503
+ const projectRoot = resolveMcpProjectRoot(args.project_path);
2504
+ const state = await getMcpHealthState(projectRoot);
2505
+ return state.evidence;
2506
+ } catch (error) {
2507
+ return { error: error.message };
2508
+ }
2509
+ }
2510
+ case "decantr_workspace_health": {
2511
+ if (args.workspace_root != null && typeof args.workspace_root !== "string") {
2512
+ return { error: "Invalid workspace_root. Must be a string when provided." };
2513
+ }
2514
+ if (args.max_projects != null && (typeof args.max_projects !== "number" || !Number.isFinite(args.max_projects))) {
2515
+ return { error: "Invalid max_projects. Must be a finite number when provided." };
2516
+ }
2517
+ try {
2518
+ return await getMcpWorkspaceHealth(args);
2519
+ } catch (error) {
2520
+ return { error: error.message };
2521
+ }
2522
+ }
2523
+ case "decantr_get_repair_prompt": {
2524
+ if (args.finding_id != null && typeof args.finding_id !== "string") {
2525
+ return { error: "Invalid finding_id. Must be a string when provided." };
2526
+ }
2527
+ try {
2528
+ const projectRoot = resolveMcpProjectRoot(args.project_path);
2529
+ const state = await getMcpHealthState(projectRoot);
2530
+ const finding = (typeof args.finding_id === "string" ? state.report.findings.find((entry) => entry.id === args.finding_id) : void 0) ?? state.report.findings.find((entry) => entry.severity === "error") ?? state.report.findings.find((entry) => entry.severity === "warn") ?? state.report.findings[0] ?? null;
2531
+ if (!finding) {
2532
+ return {
2533
+ project: state.evidence.project,
2534
+ health: state.evidence.health,
2535
+ prompt: null,
2536
+ message: "No Project Health findings require repair.",
2537
+ commands: ["decantr health --evidence"]
2538
+ };
2539
+ }
2540
+ return {
2541
+ project: state.evidence.project,
2542
+ health: state.evidence.health,
2543
+ finding: {
2544
+ id: finding.id,
2545
+ source: finding.source,
2546
+ severity: finding.severity,
2547
+ category: finding.category,
2548
+ message: finding.message
2549
+ },
2550
+ prompt: finding.remediation.prompt,
2551
+ commands: finding.remediation.commands
2552
+ };
2553
+ } catch (error) {
2554
+ return { error: error.message };
2555
+ }
2556
+ }
2557
+ case "decantr_run_health_loop": {
2558
+ if (args.finding_id != null && typeof args.finding_id !== "string") {
2559
+ return { error: "Invalid finding_id. Must be a string when provided." };
2560
+ }
2561
+ try {
2562
+ const projectRoot = resolveMcpProjectRoot(args.project_path);
2563
+ const state = await getMcpHealthState(projectRoot);
2564
+ const finding = (typeof args.finding_id === "string" ? state.report.findings.find((entry) => entry.id === args.finding_id) : void 0) ?? state.report.findings.find((entry) => entry.severity === "error") ?? state.report.findings.find((entry) => entry.severity === "warn") ?? state.report.findings[0] ?? null;
2565
+ return {
2566
+ project: state.evidence.project,
2567
+ health: state.evidence.health,
2568
+ report: state.report,
2569
+ evidence: state.evidence,
2570
+ repair: finding === null ? {
2571
+ finding: null,
2572
+ prompt: null,
2573
+ commands: ["decantr health --evidence"],
2574
+ message: "No Project Health findings require repair."
2575
+ } : {
2576
+ finding: {
2577
+ id: finding.id,
2578
+ source: finding.source,
2579
+ severity: finding.severity,
2580
+ category: finding.category,
2581
+ message: finding.message
2582
+ },
2583
+ prompt: finding.remediation.prompt,
2584
+ commands: finding.remediation.commands
2585
+ }
2586
+ };
2587
+ } catch (error) {
2588
+ return { error: error.message };
2589
+ }
2590
+ }
2105
2591
  default:
2106
2592
  return { error: `Unknown tool: ${name}` };
2107
2593
  }
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- import "./chunk-MUNBODQK.js";
1
+ import "./chunk-FEXPLJKB.js";
package/package.json CHANGED
@@ -1,9 +1,11 @@
1
1
  {
2
2
  "name": "@decantr/mcp-server",
3
- "version": "2.0.0",
3
+ "version": "2.1.0",
4
4
  "mcpName": "io.github.decantr-ai/mcp-server",
5
5
  "description": "MCP server for Decantr — exposes design intelligence, packs, and verification to AI coding assistants",
6
6
  "keywords": [
7
+ "decantr",
8
+ "decantr-ai",
7
9
  "mcp",
8
10
  "mcp-server",
9
11
  "model-context-protocol",
@@ -15,6 +17,7 @@
15
17
  "windsurf",
16
18
  "design-system",
17
19
  "design-intelligence",
20
+ "project-health",
18
21
  "ui-generation",
19
22
  "drift-detection"
20
23
  ],
@@ -46,9 +49,9 @@
46
49
  },
47
50
  "dependencies": {
48
51
  "@modelcontextprotocol/sdk": "^1.29.0",
49
- "@decantr/registry": "2.0.0",
50
- "@decantr/verifier": "2.0.0",
51
- "@decantr/essence-spec": "2.0.1"
52
+ "@decantr/essence-spec": "2.0.1",
53
+ "@decantr/verifier": "2.1.0",
54
+ "@decantr/registry": "2.0.0"
52
55
  },
53
56
  "scripts": {
54
57
  "build": "tsup",