@decantr/mcp-server 3.4.0 → 3.5.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
@@ -131,9 +131,9 @@ The server exposes a hard 8-tool MCP surface. Pass an `action` to select the rou
131
131
  | `decantr_context` | Read scaffold, section, page, task, and execution-pack context | `{ "action": "task", "project_path": "apps/web", "route": "/feed", "task": "improve recipe card loading" }` |
132
132
  | `decantr_graph` | Read graph snapshots, query graph nodes/edges, or traverse graph relations | `{ "action": "query", "project_path": "apps/web", "file_path": "src/app/page.tsx", "include_impact": true }` |
133
133
  | `decantr_registry` | Search and resolve hosted registry content, benchmarks, and execution packs | `{ "action": "resolve_pattern", "id": "data-table", "preset": "product" }` |
134
- | `decantr_verify` | Run audit, critique, findings, evidence, or health-loop reads | `{ "action": "critique", "file_path": "./src/pages/Overview.tsx" }` |
135
- | `decantr_repair` | Return typed findings, repair plans, repair prompts, and repair loop guidance | `{ "action": "repair_plan", "project_path": "apps/web", "code": "TOKEN010" }` |
136
- | `decantr_contract_write` | Explicit write surface for accepting drift or mutating Essence v4 | `{ "action": "update_essence", "operation": "add_feature", "payload": { "feature": "billing" } }` |
134
+ | `decantr_verify` | Run audit, critique, findings, v2 evidence bundles, or health-loop reads | `{ "action": "evidence_bundle", "project_path": "apps/web" }` |
135
+ | `decantr_repair` | Return typed findings, repair plans, repair prompts, and v2 health-loop guidance | `{ "action": "health_loop", "project_path": "apps/web" }` |
136
+ | `decantr_contract_write` | Explicit write surface for accepting drift, deferring drift to the drift log, or mutating Essence v4 | `{ "action": "update_essence", "operation": "add_feature", "payload": { "feature": "billing" } }` |
137
137
 
138
138
  For the broader product surface and support policy, see the root Decantr docs and package support matrix.
139
139
 
@@ -141,7 +141,7 @@ For Decantr 3 assistant prompt migration, see the MCP migration guide: https://d
141
141
 
142
142
  ## Security And Permissions
143
143
 
144
- The MCP server reads Decantr files, including `.decantr/graph` typed graph artifacts, and selected project files from the active workspace. Write access is limited to the explicit `decantr_contract_write` tool with `accept_drift` and `update_essence` actions, and paths are contained to the active workspace root.
144
+ The MCP server reads Decantr files, including `.decantr/graph` typed graph artifacts, and selected project files from the active workspace. Write access is limited to the explicit `decantr_contract_write` tool with `accept_drift` and `update_essence` actions. `accept_drift` may defer a finding to `.decantr/drift-log.json` when the caller explicitly requests that resolution. Paths are contained to the active workspace root.
145
145
 
146
146
  Registry and pack-resolution tools may call the configured Decantr API. Source upload fallbacks for hosted critique/audit are disabled unless the tool call explicitly passes `allow_hosted_upload: true`. The MCP server does not emit Decantr telemetry. See [security permissions](https://decantr.ai/reference/security-permissions.md).
147
147
 
@@ -155,7 +155,7 @@ Registry and pack-resolution tools may call the configured Decantr API. Source u
155
155
 
156
156
  ### 3.4 Tool Surface Migration
157
157
 
158
- Decantr 3.4 consolidates legacy MCP tool names into the eight action-based tools above. For example, `decantr_get_project_state` becomes `decantr_project` with `{ "action": "state" }`, `decantr_get_graph_snapshot` becomes `decantr_graph` with `{ "action": "snapshot" }`, and the legacy write tools become `decantr_contract_write` with `{ "action": "accept_drift" }` or `{ "action": "update_essence" }`.
158
+ Decantr 3.4 consolidated legacy MCP tool names into the eight action-based tools above. Decantr 3.5 keeps that surface and upgrades task, evidence, workspace health, and health-loop responses to v2 loop/evidence contracts. For example, `decantr_get_project_state` becomes `decantr_project` with `{ "action": "state" }`, `decantr_get_graph_snapshot` becomes `decantr_graph` with `{ "action": "snapshot" }`, and the legacy write tools become `decantr_contract_write` with `{ "action": "accept_drift" }` or `{ "action": "update_essence" }`.
159
159
 
160
160
  ## How It Works
161
161
 
@@ -172,8 +172,8 @@ The AI assistant calls these tools behind the scenes:
172
172
  3. `decantr_context` with `execution_pack` or `task` actions to load the compact task contract before editing
173
173
  4. `decantr_project` with `state` to check Essence, packs, graph readiness, local law, diagnostics, and next useful action calls
174
174
  5. `decantr_contract` with `capsule` and `decantr_graph` with `snapshot`, `query`, or `traverse` to read typed graph context
175
- 6. `decantr_verify` with `critique`, `audit_project`, or `evidence_bundle` to produce local evidence; hosted upload remains opt-in with `allow_hosted_upload: true`
176
- 7. `decantr_repair` with `findings`, `repair_plan`, or `repair_prompt` to enter a scoped evidence-backed repair loop
175
+ 6. `decantr_verify` with `critique`, `audit_project`, or `evidence_bundle` to produce local v2 evidence; hosted upload remains opt-in with `allow_hosted_upload: true`
176
+ 7. `decantr_repair` with `findings`, `repair_plan`, `repair_prompt`, or `health_loop` to enter a scoped evidence-backed repair loop
177
177
 
178
178
  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.
179
179
 
package/dist/bin.js CHANGED
@@ -1,2 +1,2 @@
1
1
  #!/usr/bin/env node
2
- import "./chunk-BXY4AIGA.js";
2
+ import "./chunk-PE63BVJB.js";
@@ -31,8 +31,14 @@ import {
31
31
  import {
32
32
  anchorFindingsToGraph,
33
33
  buildProjectHealthRepairPlan,
34
+ createAuthorityResolution,
35
+ createEvidenceTier,
36
+ createLoopReadiness,
34
37
  deriveVerificationDiagnostic,
35
- KNOWN_VERIFICATION_DIAGNOSTICS
38
+ KNOWN_VERIFICATION_DIAGNOSTICS,
39
+ LOOP_READINESS_V2_SCHEMA_URL,
40
+ PROJECT_HEALTH_REPORT_V2_SCHEMA_URL,
41
+ WORKSPACE_HEALTH_REPORT_V2_SCHEMA_URL
36
42
  } from "@decantr/verifier";
37
43
 
38
44
  // src/helpers.ts
@@ -1232,8 +1238,8 @@ var WRITE_TOOL = {
1232
1238
  idempotentHint: false,
1233
1239
  openWorldHint: false
1234
1240
  };
1235
- var MCP_PROJECT_HEALTH_SCHEMA_URL = "https://decantr.ai/schemas/project-health-report.v1.json";
1236
- var MCP_WORKSPACE_HEALTH_SCHEMA_URL = "https://decantr.ai/schemas/workspace-health-report.v1.json";
1241
+ var MCP_PROJECT_HEALTH_SCHEMA_URL = PROJECT_HEALTH_REPORT_V2_SCHEMA_URL;
1242
+ var MCP_WORKSPACE_HEALTH_SCHEMA_URL = WORKSPACE_HEALTH_REPORT_V2_SCHEMA_URL;
1237
1243
  var MCP_WORKSPACE_IGNORES = /* @__PURE__ */ new Set([
1238
1244
  ".git",
1239
1245
  ".next",
@@ -1504,7 +1510,8 @@ function mcpReportFromAudit(projectRoot, audit, assertions) {
1504
1510
  infoCount: anchoredFindings.filter((finding) => finding.severity === "info").length
1505
1511
  };
1506
1512
  const manifest = audit.packManifest;
1507
- return {
1513
+ const projectJson = readJsonIfExists(join2(projectRoot, ".decantr", "project.json"));
1514
+ const baseReport = {
1508
1515
  $schema: MCP_PROJECT_HEALTH_SCHEMA_URL,
1509
1516
  generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
1510
1517
  projectRoot,
@@ -1513,8 +1520,8 @@ function mcpReportFromAudit(projectRoot, audit, assertions) {
1513
1520
  summary: {
1514
1521
  ...counts,
1515
1522
  findingCount: anchoredFindings.length,
1516
- workflowMode: null,
1517
- adoptionMode: null,
1523
+ workflowMode: projectJson?.initialized?.workflowMode ?? null,
1524
+ adoptionMode: projectJson?.initialized?.adoptionMode ?? null,
1518
1525
  essenceVersion: audit.summary.essenceVersion,
1519
1526
  pageCount: audit.summary.pageCount,
1520
1527
  runtimeAuditChecked: audit.summary.runtimeAuditChecked,
@@ -1547,6 +1554,30 @@ function mcpReportFromAudit(projectRoot, audit, assertions) {
1547
1554
  },
1548
1555
  findings: anchoredFindings
1549
1556
  };
1557
+ const evidenceTier = createEvidenceTier(baseReport);
1558
+ const authority = createAuthorityResolution(baseReport);
1559
+ const loop = createLoopReadiness(baseReport, authority, evidenceTier);
1560
+ return {
1561
+ ...baseReport,
1562
+ evidenceTier,
1563
+ authority,
1564
+ loop,
1565
+ findings: anchoredFindings.map((finding) => {
1566
+ const conflict = authority.conflicts.find((entry) => entry.id === finding.id);
1567
+ return {
1568
+ ...finding,
1569
+ evidenceTier,
1570
+ authorityLane: conflict?.lane ?? authority.activeLane,
1571
+ resolutionActions: conflict?.recommendedActions,
1572
+ privacy: {
1573
+ sourceIncluded: false,
1574
+ redacted: true,
1575
+ localOnly: true
1576
+ },
1577
+ loopVerdict: loop.state
1578
+ };
1579
+ })
1580
+ };
1550
1581
  }
1551
1582
  function resolveMcpProjectRoot(value) {
1552
1583
  if (value == null) return process.cwd();
@@ -1585,6 +1616,11 @@ function compactMcpFinding(finding, includePrompt) {
1585
1616
  graph: finding.graph,
1586
1617
  repair: finding.repair,
1587
1618
  repairPlan: finding.repairPlan,
1619
+ evidenceTier: finding.evidenceTier,
1620
+ authorityLane: finding.authorityLane,
1621
+ resolutionActions: finding.resolutionActions,
1622
+ privacy: finding.privacy,
1623
+ loopVerdict: finding.loopVerdict,
1588
1624
  remediation: {
1589
1625
  summary: finding.remediation.summary,
1590
1626
  commands: finding.remediation.commands,
@@ -1777,7 +1813,9 @@ async function getMcpWorkspaceHealth(args) {
1777
1813
  durationMs: Date.now() - startedAt,
1778
1814
  changed: false,
1779
1815
  source: "auto",
1780
- error: null
1816
+ error: null,
1817
+ loopState: state.report.loop.state,
1818
+ loopNextAction: state.report.loop.nextActions[0] ?? null
1781
1819
  });
1782
1820
  } catch (error) {
1783
1821
  projects.push({
@@ -1792,23 +1830,43 @@ async function getMcpWorkspaceHealth(args) {
1792
1830
  durationMs: Date.now() - startedAt,
1793
1831
  changed: false,
1794
1832
  source: "auto",
1795
- error: error.message
1833
+ error: error.message,
1834
+ loopState: "blocked_missing_context",
1835
+ loopNextAction: "Fix the project health failure, then rerun workspace health."
1796
1836
  });
1797
1837
  }
1798
1838
  }
1839
+ const summary = {
1840
+ projectCount: discovered.length,
1841
+ checkedCount: projects.length,
1842
+ healthyCount: projects.filter((project) => project.status === "healthy").length,
1843
+ warningCount: projects.filter((project) => project.status === "warning").length,
1844
+ errorCount: projects.filter((project) => project.status === "error").length,
1845
+ failedCount: projects.filter((project) => project.status === "failed").length
1846
+ };
1847
+ const blockedCount = projects.filter(
1848
+ (project) => typeof project.loopState === "string" && (project.loopState.startsWith("blocked") || project.loopState === "human_resolution_required")
1849
+ ).length;
1850
+ const repairRequiredCount = projects.filter(
1851
+ (project) => project.loopState === "repair_required"
1852
+ ).length;
1853
+ const loopState = projects.length === 0 ? "needs_context" : blockedCount > 0 ? "human_resolution_required" : repairRequiredCount > 0 || summary.errorCount > 0 || summary.warningCount > 0 ? "repair_required" : "verified";
1799
1854
  return {
1800
1855
  $schema: MCP_WORKSPACE_HEALTH_SCHEMA_URL,
1801
1856
  generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
1802
1857
  workspaceRoot: "<workspace>",
1803
1858
  changedOnly: false,
1804
1859
  since: null,
1805
- summary: {
1806
- projectCount: discovered.length,
1807
- checkedCount: projects.length,
1808
- healthyCount: projects.filter((project) => project.status === "healthy").length,
1809
- warningCount: projects.filter((project) => project.status === "warning").length,
1810
- errorCount: projects.filter((project) => project.status === "error").length,
1811
- failedCount: projects.filter((project) => project.status === "failed").length
1860
+ summary,
1861
+ loop: {
1862
+ state: loopState,
1863
+ status: loopState === "human_resolution_required" || loopState.startsWith("blocked") ? "blocked" : summary.errorCount > 0 || summary.failedCount > 0 ? "error" : summary.warningCount > 0 ? "warning" : "healthy",
1864
+ projectCount: projects.length,
1865
+ blockedCount,
1866
+ repairRequiredCount,
1867
+ nextActions: [
1868
+ loopState === "verified" ? "Workspace loop verified." : "Open the highest-risk project, prepare task context, repair, and rerun verification."
1869
+ ]
1812
1870
  },
1813
1871
  projects
1814
1872
  };
@@ -3513,6 +3571,85 @@ async function handleLegacyTool(name, args) {
3513
3571
  },
3514
3572
  patternIds.map((id) => patternToDiscoveryCandidate({ id, name: id, description: id }))
3515
3573
  );
3574
+ const typedGraph = buildTaskTypedGraphContext(projectRoot, resolvedRoute, task, changedFiles);
3575
+ const verifyCommand = projectArg ? `decantr verify --project ${projectArg} --brownfield --local-patterns` : "decantr verify --brownfield --local-patterns";
3576
+ const loopState = typedGraph?.route_context ? "ready_to_edit" : "blocked_missing_graph";
3577
+ const loop = {
3578
+ $schema: LOOP_READINESS_V2_SCHEMA_URL,
3579
+ schemaVersion: 2,
3580
+ state: loopState,
3581
+ status: loopState === "ready_to_edit" ? "healthy" : "blocked",
3582
+ verdict: loopState === "ready_to_edit" ? "Task context is ready for an agent edit." : "Task context is missing route graph evidence.",
3583
+ summary: `${resolvedRoute ?? pageId} task context for ${task || "unspecified task"}.`,
3584
+ authority: {
3585
+ activeLane: projectJson?.initialized?.workflowMode === "brownfield-attach" ? "production-source" : "essence-contract",
3586
+ summary: "Use production source first in Brownfield, accepted local law/style bridge next, Essence V4 structure after that, and hosted packs as advisory.",
3587
+ stopRule: "If runtime source and Decantr context disagree, stop and report drift instead of guessing."
3588
+ },
3589
+ evidenceTier: {
3590
+ schemaVersion: 2,
3591
+ stage: typedGraph?.route_context ? "graph" : "static",
3592
+ status: loopState === "ready_to_edit" ? "healthy" : "incomplete",
3593
+ capabilities: typedGraph?.route_context ? ["static-audit", "project-health", "typed-graph"] : ["static-audit", "project-health"],
3594
+ coverage: {
3595
+ declaredRoutes: 1,
3596
+ runtimeRoutesChecked: 0,
3597
+ findingsAnchored: typedGraph?.route_context?.summary.openFindings ?? 0,
3598
+ findingsWithRepairPlan: 0,
3599
+ runtimeProbeCount: 0,
3600
+ visualArtifactCount: visualRoute ? 1 : 0
3601
+ },
3602
+ confidence: {
3603
+ level: typedGraph?.route_context ? "moderate" : "low",
3604
+ score: typedGraph?.route_context ? 0.64 : 0.32,
3605
+ reasons: [
3606
+ typedGraph?.route_context ? "route graph context is present" : "route graph context is missing",
3607
+ visualRoute ? "visual evidence reference is available" : "no visual evidence reference was found"
3608
+ ]
3609
+ }
3610
+ },
3611
+ blockingReasons: loopState === "ready_to_edit" ? [] : ["Route graph context is missing."],
3612
+ nextActions: loopState === "ready_to_edit" ? ["Edit only after reading the returned context, then run the verify command."] : ["Run `decantr graph`, then request task context again."],
3613
+ maker: {
3614
+ title: "Maker instructions",
3615
+ instructions: [
3616
+ "Read returned route, section, local-law, style-bridge, and graph context before editing.",
3617
+ "Preserve the active authority lane and production behavior outside this task.",
3618
+ "Stop and report drift when runtime source and Decantr context disagree."
3619
+ ]
3620
+ },
3621
+ checker: {
3622
+ title: "Checker instructions",
3623
+ instructions: [
3624
+ "Rerun the verify command after edits.",
3625
+ "Use typed graph impact to decide whether nearby routes need review.",
3626
+ "Treat advisory critique as warning-level unless runtime evidence proves a failure."
3627
+ ]
3628
+ },
3629
+ readTargets: [
3630
+ pageManifest ? join2(".decantr", "context", pageManifest.markdown) : null,
3631
+ sectionManifest ? join2(".decantr", "context", sectionManifest.markdown) : null,
3632
+ ".decantr/context/scaffold.md",
3633
+ "DECANTR.md",
3634
+ displayedLocalLaw.patterns_path,
3635
+ displayedLocalLaw.rules_path,
3636
+ displayedStyleBridge.path,
3637
+ typedGraph ? ".decantr/graph/graph.snapshot.json" : null
3638
+ ].filter(Boolean),
3639
+ graphImpact: {
3640
+ status: typedGraph?.route_context ? "ready" : typedGraph ? "stale" : "missing",
3641
+ snapshotId: typedGraph?.snapshot_id ?? null,
3642
+ sourceHash: typedGraph?.source_hash ?? null,
3643
+ sourceArtifactCount: typedGraph?.route_context?.summary.sourceArtifacts ?? 0,
3644
+ staleArtifacts: typedGraph?.stale_sources ?? []
3645
+ },
3646
+ stopConditions: [
3647
+ "Runtime source and Decantr context disagree.",
3648
+ "The route graph cannot resolve a source file affected by the edit.",
3649
+ "A fix requires contract/source/local-law mutation outside the explicit workflow."
3650
+ ],
3651
+ verifyCommand
3652
+ };
3516
3653
  return {
3517
3654
  route: resolvedRoute,
3518
3655
  page_id: pageId,
@@ -3568,8 +3705,9 @@ async function handleLegacyTool(name, args) {
3568
3705
  changed_file_count: changedFiles.length,
3569
3706
  impacted_routes: changedRoutes
3570
3707
  },
3571
- typed_graph: buildTaskTypedGraphContext(projectRoot, resolvedRoute, task, changedFiles),
3572
- verify_command: projectArg ? `decantr verify --project ${projectArg} --brownfield --local-patterns` : "decantr verify --brownfield --local-patterns",
3708
+ typed_graph: typedGraph,
3709
+ loop,
3710
+ verify_command: verifyCommand,
3573
3711
  local_files: {
3574
3712
  page_pack: displayProjectFile(
3575
3713
  projectRoot,
@@ -4001,6 +4139,9 @@ async function handleLegacyTool(name, args) {
4001
4139
  return {
4002
4140
  project: state.evidence.project,
4003
4141
  health: state.evidence.health,
4142
+ loop: state.report.loop,
4143
+ authority_resolution: state.report.authority,
4144
+ evidence_tier: state.report.evidenceTier,
4004
4145
  report: state.report,
4005
4146
  evidence: state.evidence,
4006
4147
  repair_plan: buildMcpRepairPlan({
@@ -4188,7 +4329,7 @@ function describeUpdate(operation, payload) {
4188
4329
  }
4189
4330
 
4190
4331
  // src/index.ts
4191
- var VERSION = "3.4.0";
4332
+ var VERSION = "3.5.0";
4192
4333
  var server = new Server({ name: "decantr", version: VERSION }, { capabilities: { tools: {} } });
4193
4334
  server.setRequestHandler(ListToolsRequestSchema, async () => {
4194
4335
  return { tools: TOOLS };
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- import "./chunk-BXY4AIGA.js";
1
+ import "./chunk-PE63BVJB.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@decantr/mcp-server",
3
- "version": "3.4.0",
3
+ "version": "3.5.0",
4
4
  "mcpName": "io.github.decantr-ai/mcp-server",
5
5
  "description": "MCP server for Decantr — exposes Contract context, typed graph artifacts, and verification evidence to AI coding assistants",
6
6
  "keywords": [
@@ -51,9 +51,9 @@
51
51
  },
52
52
  "dependencies": {
53
53
  "@modelcontextprotocol/sdk": "^1.29.0",
54
- "@decantr/core": "3.4.0",
55
- "@decantr/verifier": "3.4.0",
54
+ "@decantr/core": "3.5.0",
56
55
  "@decantr/essence-spec": "3.4.0",
56
+ "@decantr/verifier": "3.5.0",
57
57
  "@decantr/registry": "3.4.0"
58
58
  },
59
59
  "scripts": {