@bettercms-ai/mcp 0.42.0 → 0.43.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 CHANGED
@@ -2273,6 +2273,11 @@ function toField(f) {
2273
2273
  ...f.config ? { config: f.config } : {}
2274
2274
  };
2275
2275
  }
2276
+ var STRUCTURE_NOTE = 'ORGANISATION ONLY: folders never change a URL, slug, content or publish state, and nothing is rebuilt or delivered. Folders nest at most 4 levels deep (a page or collection may sit in a level-4 folder). Icons are lucide icon names, e.g. "folder", "file-text", "rows-3", "house" (a-z, 0-9 and dashes); null clears one.';
2277
+ function structureResult(d) {
2278
+ const message = d?.message;
2279
+ return ok(typeof message === "string" ? message : "Updated the Content structure.", d);
2280
+ }
2276
2281
  function ok(summary, data) {
2277
2282
  return {
2278
2283
  content: [
@@ -2927,6 +2932,94 @@ function buildToolDefs(deps) {
2927
2932
  z.object({ formId: z.string().min(1), submissionId: z.string().min(1) }).shape,
2928
2933
  async (c, a) => ok("Deleted submission.", await data(c, "DELETE", `/management/forms/${s(a.formId)}/submissions/${s(a.submissionId)}`))
2929
2934
  ),
2935
+ // ── Content structure: the Content sidebar's folders and icons (CPO-127 f) ──
2936
+ def(
2937
+ "get_content_structure",
2938
+ "Get the Content sidebar structure",
2939
+ `Read the Content sidebar's structure for the connected project: its folders, which pages and collections sit in each, and their icons. Returns { doc, version, summary }: \`doc\` is the raw document ({ schema: 1, folders: [{ id, parentId, name, icon, sort }], items: [{ kind: 'page'|'collection', id, folderId, sort, icon }] }), \`version\` is what set_content_structure needs, and \`summary\` is the resolved tree with page and collection TITLES (\`outline\` is a readable version), ids that no longer resolve (\`missing\`), and the pages and collections not in any folder yet. Call it before changing the structure. ${STRUCTURE_NOTE}`,
2940
+ z.object({}).shape,
2941
+ async (c) => {
2942
+ const d = await data(c, "GET", `/management/content-structure`);
2943
+ return ok(d?.summary?.outline ? `Content structure:
2944
+ ${d.summary.outline}` : "Content structure.", d);
2945
+ }
2946
+ ),
2947
+ def(
2948
+ "set_content_structure",
2949
+ "Replace the Content sidebar structure",
2950
+ `Replace the whole Content sidebar document in one write. Prefer the single-action tools (create_folder, rename_folder, move_to_folder, set_icon, delete_folder) for small changes; use this to lay out a full structure at once. Send the complete \`doc\` and the \`version\` get_content_structure returned (0 when the project has none yet). Validated exactly like the dashboard: unique folder ids, every parentId/folderId must be a folder in the doc, no cycles, depth at most 4, names 1-80 chars, lucide icon names. A 412 VERSION_CONFLICT means someone changed it since you read it: call get_content_structure again and re-apply your change. Returns the new version and a diff (folders added, removed, renamed or moved; items moved; icons changed). ${STRUCTURE_NOTE}`,
2951
+ z.object({
2952
+ doc: z.object({
2953
+ schema: z.literal(1),
2954
+ folders: z.array(z.object({
2955
+ id: z.string().min(1).describe("your own stable id, up to 64 chars"),
2956
+ parentId: z.string().nullable().describe("parent folder id; null = top level"),
2957
+ name: z.string(),
2958
+ icon: z.string().nullable().describe("lucide icon name or null"),
2959
+ sort: z.number()
2960
+ })),
2961
+ items: z.array(z.object({
2962
+ kind: z.enum(["page", "collection"]),
2963
+ id: z.string().min(1).describe("page id or collection (content model) id"),
2964
+ folderId: z.string().nullable().describe("folder id; null = its home (Static pages for a page, the Collections list for a collection)"),
2965
+ sort: z.number(),
2966
+ icon: z.string().nullable()
2967
+ }))
2968
+ }).describe("the complete document"),
2969
+ version: z.number().int().min(0).describe("the version get_content_structure returned")
2970
+ }).shape,
2971
+ async (c, a) => structureResult(await data(c, "PUT", `/management/content-structure`, { doc: a.doc, version: a.version }))
2972
+ ),
2973
+ def(
2974
+ "create_folder",
2975
+ "Create a Content sidebar folder",
2976
+ `Create a folder in the Content sidebar, at the top level or inside \`parentId\`, placed after what is already there. Returns the new \`folderId\`. Reads, applies and writes with the version check, retrying once on a conflict. ${STRUCTURE_NOTE}`,
2977
+ z.object({
2978
+ name: z.string().min(1).describe("the folder's label, 1-80 chars"),
2979
+ parentId: z.string().min(1).optional().describe("optional parent folder id (from get_content_structure); omit for the top level"),
2980
+ icon: z.string().min(1).optional().describe("optional lucide icon name, e.g. 'folder'")
2981
+ }).shape,
2982
+ async (c, a) => structureResult(await data(c, "POST", `/management/content-structure/folders`, { name: a.name, parentId: a.parentId, icon: a.icon }))
2983
+ ),
2984
+ def(
2985
+ "rename_folder",
2986
+ "Rename a Content sidebar folder",
2987
+ `Rename a Content sidebar folder. ${STRUCTURE_NOTE}`,
2988
+ z.object({
2989
+ folderId: z.string().min(1).describe("folder id (from get_content_structure)"),
2990
+ name: z.string().min(1).describe("the new label, 1-80 chars")
2991
+ }).shape,
2992
+ async (c, a) => structureResult(await data(c, "PATCH", `/management/content-structure/folders/${encodeURIComponent(s(a.folderId))}`, { name: a.name }))
2993
+ ),
2994
+ def(
2995
+ "move_to_folder",
2996
+ "Move into a Content sidebar folder",
2997
+ `Move a page, a collection or a folder into a folder. folderId null moves it back to its home: Static pages for a page, the Collections list for a collection, the top level for a folder. It lands after what is already there. Moving a folder takes its contents with it and is refused if the result would nest deeper than 4 levels or put a folder inside itself. ${STRUCTURE_NOTE}`,
2998
+ z.object({
2999
+ kind: z.enum(["page", "collection", "folder"]),
3000
+ id: z.string().min(1).describe("the page id, collection (content model) id, or folder id"),
3001
+ folderId: z.string().min(1).nullable().describe("target folder id, or null to move it back to its home (Static pages, the Collections list, or the top level for a folder)")
3002
+ }).shape,
3003
+ async (c, a) => structureResult(await data(c, "POST", `/management/content-structure/move`, { kind: a.kind, id: a.id, folderId: a.folderId }))
3004
+ ),
3005
+ def(
3006
+ "set_icon",
3007
+ "Set a Content sidebar icon",
3008
+ `Set or clear the sidebar icon of a page, a collection or a folder. ${STRUCTURE_NOTE}`,
3009
+ z.object({
3010
+ kind: z.enum(["page", "collection", "folder"]),
3011
+ id: z.string().min(1).describe("the page id, collection (content model) id, or folder id"),
3012
+ icon: z.string().min(1).nullable().describe("lucide icon name, e.g. 'file-text'; null clears it")
3013
+ }).shape,
3014
+ async (c, a) => structureResult(await data(c, "POST", `/management/content-structure/icon`, { kind: a.kind, id: a.id, icon: a.icon }))
3015
+ ),
3016
+ def(
3017
+ "delete_folder",
3018
+ "Delete a folder (its contents move up; nothing is deleted)",
3019
+ `Delete a folder (its contents move up; nothing is deleted). NOTHING ELSE IS DELETED: its pages, collections and sub-folders move up to the folder's parent, in the same order. ${STRUCTURE_NOTE}`,
3020
+ z.object({ folderId: z.string().min(1).describe("folder id (from get_content_structure)") }).shape,
3021
+ async (c, a) => structureResult(await data(c, "DELETE", `/management/content-structure/folders/${encodeURIComponent(s(a.folderId))}`))
3022
+ ),
2930
3023
  def(
2931
3024
  "list_redirects",
2932
3025
  "List redirects",