@contentrain/mcp 1.11.0 → 2.0.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.
- package/dist/{apply-manager-tRqDkzBV.mjs → apply-manager-a5l93F4O.mjs} +5 -5
- package/dist/apply-manager-a5l93F4O.mjs.map +1 -0
- package/dist/content-manager-BgxF3dHu.d.mts.map +1 -1
- package/dist/{context-CrS-IvVm.mjs → context-DjglDPvj.mjs} +2 -2
- package/dist/{context-CrS-IvVm.mjs.map → context-DjglDPvj.mjs.map} +1 -1
- package/dist/core/apply-manager.mjs +4 -4
- package/dist/core/content-manager.mjs +1 -1
- package/dist/core/context.mjs +2 -2
- package/dist/core/doctor.mjs +2 -2
- package/dist/core/model-manager.d.mts +13 -4
- package/dist/core/model-manager.d.mts.map +1 -1
- package/dist/core/model-manager.mjs +1 -1
- package/dist/core/ops/index.mjs +1 -1
- package/dist/core/validator/index.d.mts.map +1 -1
- package/dist/core/validator/index.mjs +2 -2
- package/dist/{doctor-BRPXxKhx.mjs → doctor-pw8EWRFR.mjs} +2 -2
- package/dist/{doctor-BRPXxKhx.mjs.map → doctor-pw8EWRFR.mjs.map} +1 -1
- package/dist/git/transaction.mjs +3 -3
- package/dist/index.mjs +9 -9
- package/dist/{local-DqmDeNxI.mjs → local-EJTxd5MR.mjs} +4 -4
- package/dist/{local-DqmDeNxI.mjs.map → local-EJTxd5MR.mjs.map} +1 -1
- package/dist/{model-manager-SiesTJrS.mjs → model-manager-DP2CZiMT.mjs} +92 -9
- package/dist/model-manager-DP2CZiMT.mjs.map +1 -0
- package/dist/{ops-B422KP_S.mjs → ops-CGKIKwDc.mjs} +2 -1
- package/dist/ops-CGKIKwDc.mjs.map +1 -0
- package/dist/providers/local/index.mjs +5 -5
- package/dist/server/http/index.mjs +9 -9
- package/dist/{server-DSEl2wzT.mjs → server-DKbnhtvV.mjs} +62 -18
- package/dist/server-DKbnhtvV.mjs.map +1 -0
- package/dist/server.mjs +9 -9
- package/dist/{transaction-BHOsiEn1.mjs → transaction-DC_dNON9.mjs} +2 -2
- package/dist/{transaction-BHOsiEn1.mjs.map → transaction-DC_dNON9.mjs.map} +1 -1
- package/dist/{validator-Ck0puppQ.mjs → validator-D5VncJ8M.mjs} +100 -82
- package/dist/validator-D5VncJ8M.mjs.map +1 -0
- package/package.json +2 -2
- package/dist/apply-manager-tRqDkzBV.mjs.map +0 -1
- package/dist/model-manager-SiesTJrS.mjs.map +0 -1
- package/dist/ops-B422KP_S.mjs.map +0 -1
- package/dist/server-DSEl2wzT.mjs.map +0 -1
- package/dist/validator-Ck0puppQ.mjs.map +0 -1
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
import { i as planContentDelete, n as planModelDelete, r as planContentSave, t as planModelSave } from "./ops-
|
|
1
|
+
import { i as planContentDelete, n as planModelDelete, r as planContentSave, t as planModelSave } from "./ops-CGKIKwDc.mjs";
|
|
2
2
|
import { n as contentFilePath, t as contentDirPath } from "./paths-CmVw5Cw2.mjs";
|
|
3
3
|
import { a as readJson, n as ensureDir, r as pathExists, s as writeJson, t as contentrainDir } from "./fs-DLbVB-Ek.mjs";
|
|
4
4
|
import { a as writeMetaEntries, i as writeMeta, r as readMeta } from "./meta-manager-CJUiTgP2.mjs";
|
|
5
5
|
import { n as readVocabulary, t as readConfig } from "./config-oxxgznz7.mjs";
|
|
6
|
-
import { S as writeContent, _ as resolveMdFilePath, a as fieldDefZodSchema, c as validateModelDefinition, d as listContent, g as resolveLocaleStrategy, h as resolveJsonFilePath, l as writeModel, m as resolveContentDir, n as checkReferences, o as listModels, r as countEntries, s as readModel, u as deleteContent } from "./model-manager-
|
|
7
|
-
import { n as readContext } from "./context-
|
|
6
|
+
import { S as writeContent, _ as resolveMdFilePath, a as fieldDefZodSchema, c as validateModelDefinition, d as listContent, g as resolveLocaleStrategy, h as resolveJsonFilePath, l as writeModel, m as resolveContentDir, n as checkReferences, o as listModels, r as countEntries, s as readModel, u as deleteContent } from "./model-manager-DP2CZiMT.mjs";
|
|
7
|
+
import { n as readContext } from "./context-DjglDPvj.mjs";
|
|
8
8
|
import { a as deleteRemoteBranch, c as pruneMergedRemoteBranches, i as cleanupMergedBranches, n as checkBranchHealth, s as listRemoteCrBranches } from "./branch-lifecycle-BAfgSQBv.mjs";
|
|
9
|
-
import { i as mergeBranch, n as createTransaction, r as ensureContentBranch, t as buildBranchName } from "./transaction-
|
|
10
|
-
import { n as isMerged, t as LocalProvider } from "./local-
|
|
9
|
+
import { i as mergeBranch, n as createTransaction, r as ensureContentBranch, t as buildBranchName } from "./transaction-DC_dNON9.mjs";
|
|
10
|
+
import { n as isMerged, t as LocalProvider } from "./local-EJTxd5MR.mjs";
|
|
11
11
|
import { n as isToolAvailable, t as TOOL_REQUIREMENTS } from "./availability-sWWRz2W0.mjs";
|
|
12
12
|
import { t as detectStack } from "./detect-wVSI9VuY.mjs";
|
|
13
13
|
import { t as TOOL_ANNOTATIONS } from "./annotations-D3tlsF38.mjs";
|
|
14
14
|
import { n as listTemplates, t as getTemplate } from "./templates-D6EllixQ.mjs";
|
|
15
|
-
import { t as validateProject } from "./validator-
|
|
15
|
+
import { t as validateProject } from "./validator-D5VncJ8M.mjs";
|
|
16
16
|
import { t as OverlayReader } from "./overlay-reader-BOb105gS.mjs";
|
|
17
17
|
import { t as buildGraph } from "./graph-builder-CRUX_8mA.mjs";
|
|
18
18
|
import { n as scanSummary, t as scanCandidates } from "./scanner-VOwrKLGC.mjs";
|
|
19
|
-
import { n as applyExtract, r as applyReuse } from "./apply-manager-
|
|
20
|
-
import { t as runDoctor } from "./doctor-
|
|
19
|
+
import { n as applyExtract, r as applyReuse } from "./apply-manager-a5l93F4O.mjs";
|
|
20
|
+
import { t as runDoctor } from "./doctor-pw8EWRFR.mjs";
|
|
21
21
|
import { join } from "node:path";
|
|
22
22
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
23
23
|
import { CONTENTRAIN_BRANCH } from "@contentrain/types";
|
|
@@ -830,7 +830,7 @@ function registerModelTools(server, provider, projectRoot) {
|
|
|
830
830
|
}],
|
|
831
831
|
isError: true
|
|
832
832
|
};
|
|
833
|
-
const errors = validateModel(input);
|
|
833
|
+
const { errors, warnings: schemaWarnings } = validateModel(input);
|
|
834
834
|
if (errors.length > 0) return {
|
|
835
835
|
content: [{
|
|
836
836
|
type: "text",
|
|
@@ -924,6 +924,7 @@ function registerModelTools(server, provider, projectRoot) {
|
|
|
924
924
|
valid: true,
|
|
925
925
|
errors: []
|
|
926
926
|
},
|
|
927
|
+
...schemaWarnings.length > 0 ? { schema_warnings: schemaWarnings } : {},
|
|
927
928
|
git: {
|
|
928
929
|
branch,
|
|
929
930
|
action: workflowAction,
|
|
@@ -934,7 +935,7 @@ function registerModelTools(server, provider, projectRoot) {
|
|
|
934
935
|
content_path: contentPath + "/",
|
|
935
936
|
...displayPath ? { example_file: displayPath } : {},
|
|
936
937
|
...importSnippet ? { import_snippet: importSnippet } : {},
|
|
937
|
-
next_steps: ["Add content with contentrain_content_save"]
|
|
938
|
+
next_steps: [...schemaWarnings.length > 0 ? ["REVIEW: see schema_warnings — some declared constraints are not enforced by MCP"] : [], "Add content with contentrain_content_save"]
|
|
938
939
|
}, null, 2)
|
|
939
940
|
}] };
|
|
940
941
|
});
|
|
@@ -1133,6 +1134,19 @@ function registerContentTools(server, provider, projectRoot) {
|
|
|
1133
1134
|
};
|
|
1134
1135
|
}
|
|
1135
1136
|
const entryIds = plan.result.map((r) => r.id ?? r.slug ?? r.locale).filter((v) => Boolean(v));
|
|
1137
|
+
const validationResult = await validateProject(new OverlayReader(provider, plan.changes), { model: input.model });
|
|
1138
|
+
const blocking = validationResult.issues.filter((i) => i.severity === "error" && touchesSavedEntries(i, plan.result));
|
|
1139
|
+
if (blocking.length > 0) return {
|
|
1140
|
+
content: [{
|
|
1141
|
+
type: "text",
|
|
1142
|
+
text: JSON.stringify({
|
|
1143
|
+
error: "Validation failed — nothing was written.",
|
|
1144
|
+
issues: blocking.map(describeIssue),
|
|
1145
|
+
hint: "Fix the values and call contentrain_content_save again. Nothing was committed, so there is no branch to clean up."
|
|
1146
|
+
}, null, 2)
|
|
1147
|
+
}],
|
|
1148
|
+
isError: true
|
|
1149
|
+
};
|
|
1136
1150
|
const branch = buildBranchName("content", input.model);
|
|
1137
1151
|
const message = `[contentrain] content: ${input.model}`;
|
|
1138
1152
|
const contextPayload = {
|
|
@@ -1163,8 +1177,8 @@ function registerContentTools(server, provider, projectRoot) {
|
|
|
1163
1177
|
isError: true
|
|
1164
1178
|
};
|
|
1165
1179
|
}
|
|
1166
|
-
const validationResult = await validateProject(new OverlayReader(provider, plan.changes), { model: input.model });
|
|
1167
1180
|
const allAdvisories = plan.result.flatMap((r) => r.advisories ?? []);
|
|
1181
|
+
const warnings = validationResult.issues.filter((i) => i.severity === "warning" && touchesSavedEntries(i, plan.result)).map((i) => `${i.field ?? i.locale}: ${i.message}`);
|
|
1168
1182
|
return { content: [{
|
|
1169
1183
|
type: "text",
|
|
1170
1184
|
text: JSON.stringify({
|
|
@@ -1181,14 +1195,15 @@ function registerContentTools(server, provider, projectRoot) {
|
|
|
1181
1195
|
advisories: allAdvisories,
|
|
1182
1196
|
advisory_note: "Save succeeded. Review these warnings and consider consolidating duplicate values."
|
|
1183
1197
|
} : {},
|
|
1198
|
+
...warnings.length > 0 ? { warnings } : {},
|
|
1184
1199
|
validation: {
|
|
1185
|
-
valid:
|
|
1186
|
-
errors:
|
|
1200
|
+
valid: true,
|
|
1201
|
+
errors: []
|
|
1187
1202
|
},
|
|
1188
1203
|
context_updated: true,
|
|
1189
1204
|
next_steps: [
|
|
1190
1205
|
...allAdvisories.length > 0 ? ["ADVISORY: Duplicate values detected — review advisories above"] : [],
|
|
1191
|
-
|
|
1206
|
+
...warnings.length > 0 ? ["REVIEW: see warnings above — the save was not blocked by them"] : [],
|
|
1192
1207
|
...model.kind === "collection" ? ["Use contentrain_content_list to verify", "Add more entries or publish"] : ["Use contentrain_content_list to verify"]
|
|
1193
1208
|
]
|
|
1194
1209
|
}, null, 2)
|
|
@@ -1345,6 +1360,35 @@ function registerContentTools(server, provider, projectRoot) {
|
|
|
1345
1360
|
}
|
|
1346
1361
|
});
|
|
1347
1362
|
}
|
|
1363
|
+
/** Trim a validation issue to the fields that locate it, dropping empty ones. */
|
|
1364
|
+
function describeIssue(issue) {
|
|
1365
|
+
const out = {};
|
|
1366
|
+
if (issue.entry) out["entry"] = issue.entry;
|
|
1367
|
+
if (issue.slug) out["slug"] = issue.slug;
|
|
1368
|
+
if (issue.locale) out["locale"] = issue.locale;
|
|
1369
|
+
if (issue.field) out["field"] = issue.field;
|
|
1370
|
+
out["message"] = issue.message;
|
|
1371
|
+
return out;
|
|
1372
|
+
}
|
|
1373
|
+
/**
|
|
1374
|
+
* Does a validation issue belong to one of the entries this save is writing?
|
|
1375
|
+
*
|
|
1376
|
+
* The write gate blocks on errors, but `validateProject` inspects the whole model.
|
|
1377
|
+
* Without this filter, a pre-existing bad entry somewhere else in the model would
|
|
1378
|
+
* block an unrelated — and perfectly valid — save, leaving the caller stuck behind
|
|
1379
|
+
* a problem they did not create and may not be able to fix.
|
|
1380
|
+
*
|
|
1381
|
+
* Matching is by identity: entry ID for collections, slug for documents, and
|
|
1382
|
+
* locale alone for singletons and dictionaries, which have one record per locale.
|
|
1383
|
+
*/
|
|
1384
|
+
function touchesSavedEntries(issue, results) {
|
|
1385
|
+
return results.some((r) => {
|
|
1386
|
+
if (issue.locale && r.locale && issue.locale !== r.locale) return false;
|
|
1387
|
+
if (r.id) return issue.entry === r.id;
|
|
1388
|
+
if (r.slug) return issue.slug === r.slug;
|
|
1389
|
+
return !issue.entry && !issue.slug;
|
|
1390
|
+
});
|
|
1391
|
+
}
|
|
1348
1392
|
//#endregion
|
|
1349
1393
|
//#region src/tools/workflow.ts
|
|
1350
1394
|
/**
|
|
@@ -1391,9 +1435,9 @@ async function resolveMergeBranch(git, input) {
|
|
|
1391
1435
|
}))).toSorted((left, right) => right.t - left.t)[0].b };
|
|
1392
1436
|
}
|
|
1393
1437
|
function registerWorkflowTools(server, provider, projectRoot) {
|
|
1394
|
-
server.tool("contentrain_validate", "Validate project content against model schemas. Detects required field violations, type mismatches, broken relations, secret leaks, i18n parity issues, and more. If fix:true, auto-fixes structural issues (canonical sort, orphan meta, missing locale files) — do NOT manually edit .contentrain/ files.", {
|
|
1438
|
+
server.tool("contentrain_validate", "Validate project content against model schemas. Detects required field violations, type mismatches, broken relations, secret leaks, i18n parity issues, and more. If fix:true, auto-fixes structural issues (canonical sort, orphan meta, missing locale files, stray non-i18n meta layout) — do NOT manually edit .contentrain/ files.", {
|
|
1395
1439
|
model: z.string().optional().describe("Model ID to validate (omit for all models)"),
|
|
1396
|
-
fix: z.boolean().optional().describe("Auto-fix structural issues (canonical sort, orphan meta, missing locale files). Default: false")
|
|
1440
|
+
fix: z.boolean().optional().describe("Auto-fix structural issues (canonical sort, orphan meta, missing locale files, stray non-i18n meta layout). Default: false")
|
|
1397
1441
|
}, TOOL_ANNOTATIONS["contentrain_validate"], async (input) => {
|
|
1398
1442
|
if (input.fix && !projectRoot) return capabilityError("contentrain_validate", "localWorktree");
|
|
1399
1443
|
if (!await readConfig(provider)) return {
|
|
@@ -2557,7 +2601,7 @@ function registerMediaTools(server, provider, _projectRoot) {
|
|
|
2557
2601
|
}
|
|
2558
2602
|
//#endregion
|
|
2559
2603
|
//#region package.json
|
|
2560
|
-
var version = "
|
|
2604
|
+
var version = "2.0.1";
|
|
2561
2605
|
//#endregion
|
|
2562
2606
|
//#region src/server.ts
|
|
2563
2607
|
/**
|
|
@@ -2627,4 +2671,4 @@ function resolveServerContext(input) {
|
|
|
2627
2671
|
//#endregion
|
|
2628
2672
|
export { createServer as n, DEFAULT_INSTRUCTIONS as t };
|
|
2629
2673
|
|
|
2630
|
-
//# sourceMappingURL=server-
|
|
2674
|
+
//# sourceMappingURL=server-DKbnhtvV.mjs.map
|