@bettercms-ai/mcp 0.46.0 → 0.47.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/dist/index.js +83 -55
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2102,6 +2102,19 @@ ${JSON.stringify(STRUCTURE_EXAMPLE_PAYLOAD, null, 2)}
|
|
|
2102
2102
|
`;
|
|
2103
2103
|
|
|
2104
2104
|
// src/tools.ts
|
|
2105
|
+
async function askHuman(deps, q) {
|
|
2106
|
+
if (!deps.elicit) return { prompt: q.prompt };
|
|
2107
|
+
try {
|
|
2108
|
+
const res = await deps.elicit({
|
|
2109
|
+
message: q.message,
|
|
2110
|
+
requestedSchema: { type: "object", properties: { [q.key]: q.property }, required: [q.key] }
|
|
2111
|
+
});
|
|
2112
|
+
const picked = res.action === "accept" ? res.content?.[q.key] : void 0;
|
|
2113
|
+
if (q.accept(picked)) return { value: picked };
|
|
2114
|
+
} catch {
|
|
2115
|
+
}
|
|
2116
|
+
return { prompt: q.prompt };
|
|
2117
|
+
}
|
|
2105
2118
|
var FRAMEWORK_CHOICES = ["astro", "next", "react-ts", "other"];
|
|
2106
2119
|
var FRAMEWORK_LABELS = {
|
|
2107
2120
|
astro: "Astro \u2014 recommended default, static by default and fastest to publish",
|
|
@@ -2115,32 +2128,20 @@ var FRAMEWORK_PROMPT = [
|
|
|
2115
2128
|
"",
|
|
2116
2129
|
"Do not choose on their behalf. Sites cannot be built as plain HTML/CSS \u2014 every project is backed by one of these starters, which is what keeps its content editable in the CMS."
|
|
2117
2130
|
].join("\n");
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
}
|
|
2133
|
-
},
|
|
2134
|
-
required: ["framework"]
|
|
2135
|
-
}
|
|
2136
|
-
});
|
|
2137
|
-
const picked = res.action === "accept" ? res.content?.framework : void 0;
|
|
2138
|
-
if (typeof picked === "string" && FRAMEWORK_CHOICES.includes(picked)) {
|
|
2139
|
-
return { framework: picked };
|
|
2140
|
-
}
|
|
2141
|
-
} catch {
|
|
2142
|
-
}
|
|
2143
|
-
return { prompt: FRAMEWORK_PROMPT };
|
|
2131
|
+
function askFramework(deps) {
|
|
2132
|
+
return askHuman(deps, {
|
|
2133
|
+
key: "framework",
|
|
2134
|
+
message: "Which technology should this site be built with?",
|
|
2135
|
+
property: {
|
|
2136
|
+
type: "string",
|
|
2137
|
+
title: "Technology",
|
|
2138
|
+
description: "The frontend stack this project's starter is based on.",
|
|
2139
|
+
enum: [...FRAMEWORK_CHOICES],
|
|
2140
|
+
enumNames: FRAMEWORK_CHOICES.map((c) => FRAMEWORK_LABELS[c])
|
|
2141
|
+
},
|
|
2142
|
+
accept: (v) => typeof v === "string" && FRAMEWORK_CHOICES.includes(v),
|
|
2143
|
+
prompt: FRAMEWORK_PROMPT
|
|
2144
|
+
});
|
|
2144
2145
|
}
|
|
2145
2146
|
var AUTHORING_CHOICES = ["components", "fields"];
|
|
2146
2147
|
var AUTHORING_LABELS = {
|
|
@@ -2156,32 +2157,41 @@ var AUTHORING_PROMPT = [
|
|
|
2156
2157
|
"Recommend components unless the user says the site is schema-first.",
|
|
2157
2158
|
"Do not choose on their behalf. This is asked once per project."
|
|
2158
2159
|
].join("\n");
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2160
|
+
function askAuthoring(deps) {
|
|
2161
|
+
return askHuman(deps, {
|
|
2162
|
+
key: "preference",
|
|
2163
|
+
message: "Which authoring architecture should this site use? Components is recommended for a marketing site.",
|
|
2164
|
+
property: {
|
|
2165
|
+
type: "string",
|
|
2166
|
+
title: "Authoring architecture",
|
|
2167
|
+
description: "How this site's pages are composed. Components is recommended unless this is a schema-first site (a blog, catalogue or directory). Asked once per project.",
|
|
2168
|
+
enum: [...AUTHORING_CHOICES],
|
|
2169
|
+
enumNames: AUTHORING_CHOICES.map((c) => AUTHORING_LABELS[c])
|
|
2170
|
+
},
|
|
2171
|
+
accept: (v) => typeof v === "string" && AUTHORING_CHOICES.includes(v),
|
|
2172
|
+
prompt: AUTHORING_PROMPT
|
|
2173
|
+
});
|
|
2174
|
+
}
|
|
2175
|
+
var USE_CDN_PROMPT = [
|
|
2176
|
+
"Ask the user where this site's media should be served from, then call set_media_delivery again with their answer as `useCdn`:",
|
|
2177
|
+
" 1. true \u2014 the BetterCMS CDN (recommended, and the default). Media URLs are minted on the CDN host, or on the project's own CDN base if it stores media in its own bucket.",
|
|
2178
|
+
" 2. false \u2014 the API origin. Media URLs are minted on the API host instead. Same bytes, same service; only the hostname differs.",
|
|
2179
|
+
"",
|
|
2180
|
+
"This applies to URLs minted FROM NOW ON. Already-published content keeps the URLs it has, and they keep working."
|
|
2181
|
+
].join("\n");
|
|
2182
|
+
function askMediaDelivery(deps) {
|
|
2183
|
+
return askHuman(deps, {
|
|
2184
|
+
key: "useCdn",
|
|
2185
|
+
message: "Serve this site's media from the BetterCMS CDN (recommended), or from the API origin?",
|
|
2186
|
+
property: {
|
|
2187
|
+
type: "boolean",
|
|
2188
|
+
title: "Use the CDN",
|
|
2189
|
+
description: "On (default): media URLs are minted on the CDN \u2014 or on this project's own CDN base if it uses its own bucket. Off: they are minted on the API origin instead. Same bytes either way; only the host changes, and only for URLs minted from now on.",
|
|
2190
|
+
default: true
|
|
2191
|
+
},
|
|
2192
|
+
accept: (v) => typeof v === "boolean",
|
|
2193
|
+
prompt: USE_CDN_PROMPT
|
|
2194
|
+
});
|
|
2185
2195
|
}
|
|
2186
2196
|
var fieldType = z.enum([
|
|
2187
2197
|
"text",
|
|
@@ -3299,7 +3309,7 @@ ${d.outline}` : "Proposed Content structure.", d);
|
|
|
3299
3309
|
if (framework === void 0) {
|
|
3300
3310
|
const asked = await askFramework(deps);
|
|
3301
3311
|
if ("prompt" in asked) return fail(asked.prompt);
|
|
3302
|
-
framework = asked.
|
|
3312
|
+
framework = asked.value;
|
|
3303
3313
|
}
|
|
3304
3314
|
return ok("Created project.", await data(c, "POST", `/management/projects`, { ...a, framework }));
|
|
3305
3315
|
}
|
|
@@ -3318,7 +3328,7 @@ ${d.outline}` : "Proposed Content structure.", d);
|
|
|
3318
3328
|
if (preference === void 0) {
|
|
3319
3329
|
const asked = await askAuthoring(deps);
|
|
3320
3330
|
if ("prompt" in asked) return fail(asked.prompt);
|
|
3321
|
-
preference = asked.
|
|
3331
|
+
preference = asked.value;
|
|
3322
3332
|
}
|
|
3323
3333
|
return ok("Recorded the authoring architecture.", await data(c, "PATCH", `/management/projects/current/authoring-preference`, { preference }));
|
|
3324
3334
|
}
|
|
@@ -3330,6 +3340,24 @@ ${d.outline}` : "Proposed Content structure.", d);
|
|
|
3330
3340
|
z.object({ declaredBindings: z.boolean().describe("true = trust the template's declared bindings; false = text-match (the default)") }).shape,
|
|
3331
3341
|
async (c, a) => ok("Recorded the binding mode.", await data(c, "PATCH", `/management/projects/current/binding-mode`, { declaredBindings: a.declaredBindings }))
|
|
3332
3342
|
),
|
|
3343
|
+
def(
|
|
3344
|
+
"set_media_delivery",
|
|
3345
|
+
"Choose where this site's media is served from",
|
|
3346
|
+
"Record whether this project's media (images, video, files) is served from the BetterCMS CDN or from the API origin. `useCdn: true` is the DEFAULT and the recommendation: URLs are minted on the CDN host, or on the project's own CDN base when it stores media in its own bucket (BYOK). `useCdn: false` mints them on the API origin instead \u2014 the same service serving the same bytes, only under a different hostname. ASK THE USER; do not pick for them. Called without `useCdn`, this tool asks them directly (or hands you the question to ask). \u{1F534} IT APPLIES TO URLs MINTED FROM NOW ON \u2014 new uploads, entry saves, get_media. It does NOT rewrite URLs already stored in published content, and it does not need to: the old URLs keep resolving. To move an existing image, re-save the field that holds it. \u{1F534} IT IS THE BACKEND HALF ONLY. A deployed frontend builds its own transform URLs with @bettercms-ai/image-url, which has its own media host \u2014 set `PUBLIC_BCMS_MEDIA_URL` (or the integration's `mediaUrl` option) to match, or that site's resized images stay on the CDN while everything else moves. Read the current answer from get_project (`useCdn`). Re-callable; the last answer wins.",
|
|
3347
|
+
// Optional in the schema for the same reason `framework` and `preference` are: a
|
|
3348
|
+
// required arg is rejected by the SDK before the handler runs, which would kill the
|
|
3349
|
+
// elicitation below and leave the model guessing.
|
|
3350
|
+
z.object({ useCdn: z.boolean().optional().describe("REQUIRED in effect \u2014 the USER's answer. true = CDN (the default), false = API origin. Ask them; never default it.") }).shape,
|
|
3351
|
+
async (c, a) => {
|
|
3352
|
+
let useCdn = a.useCdn;
|
|
3353
|
+
if (useCdn === void 0) {
|
|
3354
|
+
const asked = await askMediaDelivery(deps);
|
|
3355
|
+
if ("prompt" in asked) return fail(asked.prompt);
|
|
3356
|
+
useCdn = asked.value;
|
|
3357
|
+
}
|
|
3358
|
+
return ok("Recorded the media delivery origin.", await data(c, "PATCH", `/management/projects/current/media-delivery`, { useCdn }));
|
|
3359
|
+
}
|
|
3360
|
+
),
|
|
3333
3361
|
def(
|
|
3334
3362
|
"submit_conversion_receipt",
|
|
3335
3363
|
"Record what the conversion codemod could and could not do",
|
|
@@ -6007,7 +6035,7 @@ and \`ui\` only changes editor chrome, so there is nothing to flip.`
|
|
|
6007
6035
|
|
|
6008
6036
|
// src/server.ts
|
|
6009
6037
|
var SERVER_NAME = "bettercms";
|
|
6010
|
-
var SERVER_VERSION = "1.
|
|
6038
|
+
var SERVER_VERSION = "1.5.0";
|
|
6011
6039
|
var SERVER_DISPLAY = {
|
|
6012
6040
|
title: "BetterCMS",
|
|
6013
6041
|
websiteUrl: "https://bettercms.ai",
|